Method: FFI::ConstGenerator#calculate

Defined in:
lib/ffi/tools/const_generator.rb

#calculate(options = {}) ⇒ nil

Calculate constants values.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :cppflags (String)

    flags for C compiler

Returns:

  • (nil)

Raises:

  • if a constant is missing and :required was set to true (see #initialize)



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/ffi/tools/const_generator.rb', line 107

def calculate(options = {})
  binary_path = nil

  Tempfile.open("#{@prefix}.const_generator") do |f|
    binary_path = f.path + ".bin"
    @includes.each do |inc|
      f.puts "#include <#{inc}>"
    end
    f.puts "\nint main(int argc, char **argv)\n{"

    @constants.each_value do |const|
      f.puts <<-EOF
  #ifdef #{const.name}
  printf("#{const.name} #{const.format}\\n", #{const.cast}#{const.name});
  #endif
      EOF
    end

    f.puts "\n\treturn 0;\n}"
    f.flush

    cc = ENV['CC'] || 'gcc'
    output = `#{cc} #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary_path} 2>&1`

    unless $?.success? then
      output = output.split("\n").map { |l| "\t#{l}" }.join "\n"
      raise "Compilation error generating constants #{@prefix}:\n#{output}"
    end
  end

  output = `#{binary_path}`
  File.unlink(binary_path + (FFI::Platform.windows? ? ".exe" : ""))
  output.each_line do |line|
    line =~ /^(\S+)\s(.*)$/
    const = @constants[$1]
    const.value = $2
  end

  missing_constants = @constants.select do |name, constant|
    constant.value.nil?
  end.map { |name,| name }

  if @required and not missing_constants.empty? then
    raise "Missing required constants for #{@prefix}: #{missing_constants.join ', '}"
  end
end