class ChildProcess::Tools::Generator

Constants

DEFAULT_INCLUDES
EXE_NAME
TMP_PROGRAM

Public Class Methods

generate() click to toggle source
# File lib/childprocess/tools/generator.rb, line 10
def self.generate
  new.generate
end
new() click to toggle source
# File lib/childprocess/tools/generator.rb, line 14
def initialize
  @cc        = ENV['CC'] || 'gcc'
  @out       = File.expand_path("../../unix/platform/#{ChildProcess.platform_name}.rb", __FILE__)
  @sizeof    = {}
  @constants = {}
end

Public Instance Methods

execute(src, opts) click to toggle source
# File lib/childprocess/tools/generator.rb, line 85
      def execute(src, opts)
        program = Array(opts[:define]).map do |key, value|
          <<-SRC
#ifndef #{key}
#define #{key} #{value}
#endif
          SRC
        end.join("\n")
        program << "\n"

        includes = Array(opts[:include]) + DEFAULT_INCLUDES
        program << includes.map { |include| "#include <#{include}>" }.join("\n")
        program << "\n#{src}"

        File.open(TMP_PROGRAM, 'w') do |file|
          file << program
        end

        cmd = "#{@cc} #{TMP_PROGRAM} -o #{EXE_NAME}"
        system cmd
        unless $?.success?
          raise "failed to compile program: #{cmd.inspect}\n#{program}"
        end

        output = `./#{EXE_NAME} 2>&1`

        unless $?.success?
          raise "failed to run program: #{cmd.inspect}\n#{output}"
        end

        output.chomp
      ensure
        File.delete TMP_PROGRAM if File.exist?(TMP_PROGRAM)
        File.delete EXE_NAME if File.exist?(EXE_NAME)
      end
fetch_constant(name, opts) click to toggle source
# File lib/childprocess/tools/generator.rb, line 68
      def fetch_constant(name, opts)
        print "#{name}: "
        src = <<-EOF
int main() {
  printf("%d", (unsigned int)#{name});
  return 0;
}
        EOF

        output = execute(src, opts)
        value  = Integer(output)
        @constants[name] = value

        puts value
      end
fetch_size(type_name, opts = {}) click to toggle source
# File lib/childprocess/tools/generator.rb, line 47
      def fetch_size(type_name, opts = {})
        print "sizeof(#{type_name}): "
        src = <<-EOF
int main() {
  printf("%d", (unsigned int)sizeof(#{type_name}));
  return 0;
}
        EOF

        output = execute(src, opts)

        if output.to_i < 1
          raise "sizeof(#{type_name}) == #{output.to_i} (output=#{output})"
        end

        size = output.to_i
        @sizeof[type_name] = size

        puts size
      end
generate() click to toggle source
# File lib/childprocess/tools/generator.rb, line 21
def generate
  fetch_size 'posix_spawn_file_actions_t', :include => "spawn.h"
  fetch_size 'posix_spawnattr_t', :include => "spawn.h"
  fetch_size 'sigset_t', :include => "signal.h"

  fetch_constant 'POSIX_SPAWN_RESETIDS',   :include  => 'spawn.h'
  fetch_constant 'POSIX_SPAWN_SETPGROUP',  :include  => 'spawn.h'
  fetch_constant 'POSIX_SPAWN_SETSIGDEF',  :include  => 'spawn.h'
  fetch_constant 'POSIX_SPAWN_SETSIGMASK', :include  => 'spawn.h'

  if ChildProcess.linux?
    fetch_constant 'POSIX_SPAWN_USEVFORK', :include => 'spawn.h', :define => {'_GNU_SOURCE' => nil}
  end

  write
end
result() click to toggle source
# File lib/childprocess/tools/generator.rb, line 121
def result
  if @sizeof.empty? && @constants.empty?
    raise "no data collected, nothing to do"
  end

  out =  ['module ChildProcess::Unix::Platform']
  out << '  SIZEOF = {'

  max = @sizeof.keys.map { |e| e.length }.max
  @sizeof.each_with_index do |(type, size), idx|
    out << "     :#{type.ljust max} => #{size}#{',' unless idx == @sizeof.size - 1}"
  end
  out << '  }'

  max = @constants.keys.map { |e| e.length }.max
  @constants.each do |name, val|
    out << "  #{name.ljust max} = #{val}"
  end
  out << 'end'

  out.join "\n"
end
write() click to toggle source
# File lib/childprocess/tools/generator.rb, line 38
def write
  FileUtils.mkdir_p(File.dirname(@out))
  File.open(@out, 'w') do |io|
    io.puts result
  end

  puts "wrote #{@out}"
end