Class: FFI::StructGenerator
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Inherits: | Object |
Defined in: | lib/ffi/tools/struct_generator.rb |
Overview
Generates an ::FFI
Struct layout.
Given the @@@ portion in:
class Zlib::ZStream < FFI::Struct
@@@
name "struct z_stream_s"
include "zlib.h"
field :next_in, :pointer
field :avail_in, :uint
field :total_in, :ulong
# ...
@@@
end
StructGenerator
will create the layout:
layout :next_in, :pointer, 0,
:avail_in, :uint, 4,
:total_in, :ulong, 8,
# ...
StructGenerator
does its best to pad the layout it produces to preserve line numbers. Place the struct definition as close to the top of the file for best results.
Class Attribute Summary
- .options rw
- .options=(options) rw
Class Method Summary
- .new(name, options = {}) ⇒ StructGenerator constructor
Instance Attribute Summary
- #fields readonly
- #found? ⇒ Boolean readonly
- #size rw
Instance Method Summary
Constructor Details
.new(name, options = {}) ⇒ StructGenerator
Class Attribute Details
.options (rw)
[ GitHub ]# File 'lib/ffi/tools/struct_generator.rb', line 55
def self. @options end
.options=(options) (rw)
[ GitHub ]# File 'lib/ffi/tools/struct_generator.rb', line 52
def self. ( ) @options = end
Instance Attribute Details
#fields (readonly)
[ GitHub ]# File 'lib/ffi/tools/struct_generator.rb', line 37
attr_reader :fields
#found? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/ffi/tools/struct_generator.rb', line 121
def found? @found end
#size (rw)
[ GitHub ]# File 'lib/ffi/tools/struct_generator.rb', line 36
attr_accessor :size
Instance Method Details
#calculate(options = {})
[ GitHub ]# File 'lib/ffi/tools/struct_generator.rb', line 58
def calculate( = {}) binary = File.join Dir.tmpdir, "rb_struct_gen_bin_#{Process.pid}" raise "struct name not set" if @struct_name.nil? Tempfile.open("#{@name}.struct_generator") do |f| f.puts "#include <stdio.h>" @includes.each do |inc| f.puts "#include <#{inc}>" end f.puts "#include <stddef.h>\n\n" f.puts "int main(int argc, char **argv)\n{" f.puts " #{@struct_name} s;" f.puts %[ printf("sizeof(#{@struct_name}) %u\\n", (unsigned int) sizeof(#{@struct_name}));] @fields.each do |field| f.puts <<-EOF printf("#{field.name} %u %u\\n", (unsigned int) offsetof(#{@struct_name}, #{field.name}), (unsigned int) sizeof(s.#{field.name})); EOF end f.puts "\n return 0;\n}" f.flush cc = ENV['CC'] || 'gcc' output = `#{cc} #{ [:cppflags]} #{ [:cflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary} 2>&1` unless $?.success? then @found = false output = output.split("\n").map { |l| "\t#{l}" }.join "\n" raise "Compilation error generating struct #{@name} (#{@struct_name}):\n#{output}" end end output = `#{binary}`.split "\n" File.unlink(binary + (FFI::Platform.windows? ? ".exe" : "")) sizeof = output.shift unless @size m = /\s*sizeof\([^)]+\) (\d+)/.match sizeof @size = m[1] end line_no = 0 output.each do |line| md = line.match(/.+ (\d+) (\d+)/) @fields[line_no].offset = md[1].to_i @fields[line_no].size = md[2].to_i line_no += 1 end @found = true end
#dump_config(io)
[ GitHub ]#field(name, type = nil)
[ GitHub ]#generate_layout
[ GitHub ]# File 'lib/ffi/tools/struct_generator.rb', line 131
def generate_layout buf = "" @fields.each_with_index do |field, i| if buf.empty? buf << "layout :#{field.name}, :#{field.type}, #{field.offset}" else buf << " :#{field.name}, :#{field.type}, #{field.offset}" end if i < @fields.length - 1 buf << ",\n" end end buf end
#get_field(name)
[ GitHub ]#include(i)
[ GitHub ]# File 'lib/ffi/tools/struct_generator.rb', line 153
def include(i) @includes << i end
#name(n)
[ GitHub ]# File 'lib/ffi/tools/struct_generator.rb', line 157
def name(n) @struct_name = n end