class FFI::Exporter
def attach(mname, fname, result_type, param_types)
def attach(mname, fname, result_type, param_types) @functions << { mname: mname, fname: fname, result_type: result_type, params: param_types.dup } end
def callback(name, cb)
def callback(name, cb) @callbacks[name] = cb end
def dump(out_file)
def dump(out_file) File.open(out_file, 'w') do |f| guard = File.basename(out_file).upcase.gsub('.', '_').gsub('/', '_') f.puts <<-HEADER def #{guard} ine #{guard} 1 def RBFFI_EXPORT def __cplusplus efine RBFFI_EXPORT extern "C" se efine RBFFI_EXPORT dif if HEADER @callbacks.each do |name, cb| f.puts "typedef #{cb.name(name)};" end @structs.each do |s| f.puts "struct #{s[:name].gsub('::', '_')} {" s[:fields].each do |field| if field[:type].is_a?(CallbackInfo) type = field[:type].name(field[:name].to_s) else type = "#{field[:type].name} #{field[:name].to_s}" end f.puts "#{' ' * 4}#{type};" end f.puts '};' f.puts end @functions.each do |fn| param_string = fn[:params].empty? ? 'void' : fn[:params].map(&:name).join(', ') f.puts "RBFFI_EXPORT #{fn[:result_type].name} #{fn[:fname]}(#{param_string});" end f.puts <<-EPILOG if /* #{guard} */ EPILOG end end
def initialize(mod)
def initialize(mod) @mod = mod @functions = [] @callbacks = {} @structs = [] end
def struct(name, fields)
def struct(name, fields) @structs << { name: name, fields: fields.dup } end