ffi2-generators 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f4b27c539662e9b2d469ed8e8345bb8ed5f0244
4
+ data.tar.gz: 3a6992fb5b224faf1ec1f85aacaa4b6bbbab7a4c
5
+ SHA512:
6
+ metadata.gz: b31668fd36d8fdeb444659bc7a78d7682c648a8b98e99b37f86c23eb199939944c0d6a93ee57b447b92e370dff6241bd1daa860bd5e820c86f5d066c7378dd93
7
+ data.tar.gz: 611e20ede0e0de89462f2142923154c637f0d9574550ac348220a7d82ddffc3b5a618f360c18324affe164ceb911fba2723c635cfeecbc9c489b057485497465
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ffi2-generators.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2013, Brian Shirai
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ 3. Neither the name of the library nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,29 @@
1
+ # Ffi2::Generators
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'ffi2-generators'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install ffi2-generators
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+ require './lib/ffi2/generators/version'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "ffi2-generators"
6
+ spec.version = FFI::Generators::VERSION
7
+ spec.authors = ["Brian Shirai"]
8
+ spec.email = ["brixen@gmail.com"]
9
+ spec.description = %q{Utilities for generating constants, types, and structs for FFI.}
10
+ spec.summary = %q{Utilities for generating constants, types, and structs for FFI.}
11
+ spec.homepage = "https://github.com/rubinius/ffi2-generators"
12
+ spec.license = "BSD"
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.3"
20
+ spec.add_development_dependency "rake", "~> 10.0"
21
+ end
@@ -0,0 +1,164 @@
1
+ require "ffi2/generators/version"
2
+ require "ffi2/generators/constants"
3
+ require "ffi2/generators/structures"
4
+ require "ffi2/generators/types"
5
+ require "ffi2/generators/file_processor"
6
+
7
+ require "rbconfig"
8
+
9
+ module FFI
10
+ module Generators
11
+
12
+ ##
13
+ # BodyGuard does your file system dirty work and cleans up after any
14
+ # fallout.
15
+
16
+ class BodyGuardError < Exception; end
17
+
18
+ class BodyGuard
19
+ def initialize(subject, label, platform)
20
+ @subject = subject
21
+ @label = label.gsub(/\W/, '-')
22
+ @platform = platform
23
+ end
24
+
25
+ ##
26
+ # Orchestrates a workflow by querying the subject at each stage and cleans
27
+ # up if problems arise before raising an exception.
28
+ #
29
+ # Expects the subject to respond to the following methods:
30
+ #
31
+ # #source io
32
+ # Where io is an IO instance used to create the source for later
33
+ # stages.
34
+ #
35
+ # #prepare name, target
36
+ # Where name is the source file name and target is the file that would
37
+ # be created by the prepare process. The method should return the
38
+ # command to run.
39
+ #
40
+ # #prepare_failed
41
+ # The method should return the error message for #raise to which will
42
+ # be appended the output of running the command returned by #prepare.
43
+ #
44
+ # #process target
45
+ # Where target is the same as passed to #prepare. The method should
46
+ # return the command to run. If no further options or changes are
47
+ # needed, #process should just return target.
48
+ #
49
+ # #process_failed
50
+ # The method should return the error message for #raise to which will
51
+ # be appended the output of running the command returned by #process.
52
+ #
53
+ # The #perform method returns the result of running the command returned
54
+ # by the #process method.
55
+
56
+ def perform
57
+ begin
58
+ name = "rbx-ffi-generators-#{@label}"
59
+ source = File.expand_path name + @platform.source_ext
60
+ target = File.expand_path name + @platform.executable_ext
61
+
62
+ File.open source, "wb" do |f|
63
+ @subject.source f
64
+ end
65
+
66
+ if preparer = @subject.prepare(source, target)
67
+ handle preparer, :prepare_failed
68
+ else
69
+ target = source
70
+ end
71
+
72
+ processor = @subject.process target
73
+ return handle(processor, :process_failed)
74
+ ensure
75
+ remove source, target
76
+ end
77
+ end
78
+
79
+ def handle(command, failure)
80
+ result = `#{command}`
81
+ Process.waitpid $?.pid rescue nil
82
+
83
+ unless $?.success?
84
+ result = result.split("\n").map { |l| "\t#{l}" }.join "\n"
85
+ msg = "#{@subject.send failure}:\n#{result}"
86
+ raise BodyGuardError, msg
87
+ end
88
+
89
+ result
90
+ end
91
+
92
+ def remove(*names)
93
+ names.each do |name|
94
+ File.delete name if File.exists? name
95
+ end
96
+ end
97
+ end
98
+
99
+ class Platform
100
+ # TODO: Make these configurable to enable cross-compiling
101
+
102
+ def initialize(kind=:c)
103
+ @kind = kind
104
+ end
105
+
106
+ def source_ext
107
+ case @kind
108
+ when :c
109
+ ".c"
110
+ when :cpp
111
+ ".cpp"
112
+ end
113
+ end
114
+
115
+ def executable_ext
116
+ windows? ? ".exe" : ""
117
+ end
118
+
119
+ def defines
120
+ case @kind
121
+ when :c
122
+ RbConfig::CONFIG["CFLAGS"]
123
+ when :cpp, :cxx
124
+ RbConfig::CONFIG["CPPFLAGS"] || RbConfig["CXXFLAGS"]
125
+ else
126
+ RbConfig::CONFIG["CFLAGS"]
127
+ end
128
+ end
129
+
130
+ def windows?
131
+ RUBY_PLATFORM =~ /mswin|mingw/
132
+ end
133
+
134
+ def compiler
135
+ case @kind
136
+ when :c
137
+ RbConfig::CONFIG["CC"]
138
+ when :cpp, :cxx
139
+ RbConfig::CONFIG["CXX"] || RbConfig::CONFIG["CC"]
140
+ else
141
+ RbConfig::CONFIG["CC"]
142
+ end
143
+ end
144
+
145
+ def language
146
+ case @kind
147
+ when :c
148
+ "c"
149
+ when :cpp, :cxx
150
+ "c++"
151
+ else
152
+ "c"
153
+ end
154
+ end
155
+
156
+ def compile(include_dirs, source, target)
157
+ includes = include_dirs.map { |i| "-I#{i}" }.join(" ")
158
+ compile_options = "#{defines} -x #{language} #{includes} -Wall -Werror"
159
+
160
+ "#{compiler} #{compile_options} #{source} -o #{target} 2>&1"
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,178 @@
1
+ module FFI
2
+ module Generators
3
+ ##
4
+ # Constants turns C constants into ruby values.
5
+
6
+ class Constants
7
+
8
+ class Constant
9
+ attr_reader :name, :format, :cast
10
+ attr_accessor :value
11
+
12
+ def initialize(name, format, cast, ruby_name=nil, converter=nil)
13
+ @name = name
14
+ @format = format
15
+ @cast = cast
16
+ @ruby_name = ruby_name
17
+ @converter = converter
18
+ @value = nil
19
+ end
20
+
21
+ def value?
22
+ @value != nil
23
+ end
24
+
25
+ def converted_value
26
+ @converter ? @converter.call(@value) : @value
27
+ end
28
+
29
+ def ruby_name
30
+ @ruby_name || @name
31
+ end
32
+
33
+ def to_ruby
34
+ "#{ruby_name} = #{converted_value}"
35
+ end
36
+ end
37
+
38
+
39
+ attr_reader :constants
40
+
41
+ ##
42
+ # Creates a new constant generator that uses +prefix+ as a name, and an
43
+ # options hash.
44
+ #
45
+ # The only option is :required, which if set to true raises an error if a
46
+ # constant you have requested was not found.
47
+ #
48
+ # When passed a block, #calculate is automatically called at the end of
49
+ # the block, otherwise you must call it yourself.
50
+
51
+ def initialize(prefix=nil, options={})
52
+ @includes = []
53
+ @include_dirs = []
54
+ @constants = {}
55
+ @prefix = prefix
56
+ @platform = Platform.new
57
+
58
+ @required = options[:required]
59
+
60
+ if block_given?
61
+ yield self
62
+ calculate
63
+ end
64
+ end
65
+
66
+ def [](name)
67
+ @constants[name].value
68
+ end
69
+
70
+ ##
71
+ # Request the value for C constant +name+. +format+ is a printf format
72
+ # string to print the value out, and +cast+ is a C cast for the value.
73
+ # +ruby_name+ allows you to give the constant an alternate ruby name for
74
+ # #to_ruby. +converter+ or +converter_proc+ allow you to convert the
75
+ # value from a string to the appropriate type for #to_ruby.
76
+
77
+ def const(name, format=nil, cast=nil, ruby_name=nil, converter=nil, &block)
78
+ format ||= '%ld'
79
+ cast ||= '(long)'
80
+
81
+ if block and converter
82
+ raise ArgumentError, "Supply only converter or converter block"
83
+ end
84
+
85
+ converter = block if converter.nil?
86
+
87
+ const = Constant.new name, format, cast, ruby_name, converter
88
+ @constants[name.to_s] = const
89
+ return const
90
+ end
91
+
92
+ def source(io)
93
+ io.puts "#include <stdio.h>"
94
+
95
+ @includes.each do |inc|
96
+ io.puts "#include <#{inc}>"
97
+ end
98
+
99
+ io.puts "#include <stddef.h>\n\n"
100
+ io.puts "int main(int argc, char **argv)\n{"
101
+
102
+ @constants.each_value do |const|
103
+ io.puts <<-EOF
104
+ #ifdef #{const.name}
105
+ printf("#{const.name} #{const.format}\\n", #{const.cast}#{const.name});
106
+ #endif
107
+ EOF
108
+ end
109
+
110
+ io.puts "\n\treturn 0;\n}"
111
+ end
112
+
113
+ def prepare(name, target)
114
+ @platform.compile(@include_dirs, name, target)
115
+ end
116
+
117
+ def prepare_failed
118
+ "Compilation error generating constants #{@prefix}"
119
+ end
120
+
121
+ def process(target)
122
+ target
123
+ end
124
+
125
+ def process_failed
126
+ "Error generating constants #{@prefix}"
127
+ end
128
+
129
+ def calculate
130
+ output = BodyGuard.new(self, @prefix, @platform).perform
131
+
132
+ output.each_line do |line|
133
+ line =~ /^(\S+)\s(.*)$/
134
+ const = @constants[$1]
135
+ const.value = $2
136
+ end
137
+
138
+ missing_constants = @constants.reject { |_, c| c.value? }.keys
139
+
140
+ if @required and not missing_constants.empty?
141
+ raise "Missing required constants for #{@prefix}: #{missing_constants.join ', '}"
142
+ end
143
+ end
144
+
145
+ def write_constants(io)
146
+ @constants.each do |name, constant|
147
+ io.print @prefix, "."
148
+ io.puts constant.to_ruby
149
+ end
150
+ end
151
+
152
+ ##
153
+ # Outputs values for discovered constants. If the constant's value was
154
+ # not discovered it is not omitted.
155
+
156
+ def to_ruby
157
+ @constants.sort_by { |name,| name }.map do |name, constant|
158
+ if constant.value?
159
+ constant.to_ruby
160
+ else
161
+ "# #{name} not defined"
162
+ end
163
+ end.join "\n"
164
+ end
165
+
166
+ def include(i)
167
+ @includes << i
168
+ end
169
+
170
+ def include_dir(i)
171
+ @include_dirs << i
172
+ end
173
+ end
174
+
175
+ end
176
+
177
+ ConstGenerator = Generators::Constants
178
+ end
@@ -0,0 +1,85 @@
1
+ module FFI
2
+
3
+ # Processes a file containing Ruby code with blocks of FFI definitions
4
+ # delimited by @@@. The blocks are replaced with Ruby code produced by
5
+ # running the FFI generators contained in the blocks. For example:
6
+ #
7
+ # module Something
8
+ # @@@
9
+ # constants do |c|
10
+ # c.include 'somefile.h'
11
+ #
12
+ # c.const 'MAX'
13
+ # c.const 'MIN'
14
+ # end
15
+ # @@@
16
+ # end
17
+ #
18
+ # would be converted to:
19
+ #
20
+ # module Something
21
+ # MAX = 1
22
+ # MIN = 2
23
+ # end
24
+ #
25
+ # assuming that
26
+ #
27
+ # #define MAX 1
28
+ # #define MIN 2
29
+ #
30
+ # was contained in the file 'something.h'.
31
+
32
+ class FileProcessor
33
+
34
+ def initialize(ffi_name, rb_name)
35
+ @name = File.basename rb_name, '.rb'
36
+
37
+ definitions = File.read ffi_name
38
+
39
+ replacement = definitions.gsub(/^( *)@@@(.*?)@@@/m) do
40
+ @constants = []
41
+ @structs = []
42
+
43
+ indent = $1
44
+ line_count = $2.count("\n") + 1
45
+
46
+ instance_eval $2
47
+
48
+ lines = []
49
+ @constants.each { |c| lines << c.to_ruby }
50
+ @structs.each { |s| lines << s.generate_layout }
51
+
52
+ # expand multiline blocks
53
+ lines = lines.join("\n").split "\n"
54
+ lines = lines.map { |line| indent + line }
55
+
56
+ # preserve source line numbers in output
57
+ padding = line_count - lines.length
58
+ lines += [nil] * padding if padding >= 0
59
+
60
+ lines.join "\n"
61
+ end
62
+
63
+ File.open rb_name, 'wb' do |f|
64
+ f.puts "# This file is generated #{self.class} from #{ffi_name}."
65
+ f.puts
66
+ f.puts replacement
67
+ end
68
+ end
69
+
70
+ def constants(options={}, &block)
71
+ @constants << FFI::ConstGenerator.new(@name, options, &block)
72
+ end
73
+
74
+ def struct(&block)
75
+ @structs << FFI::StructGenerator.new(@name, &block)
76
+ end
77
+
78
+ ##
79
+ # Utility converter for constants
80
+
81
+ def to_s
82
+ proc { |obj| obj.to_s.inspect }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,198 @@
1
+ module FFI
2
+ module Generators
3
+ ##
4
+ # Generates an FFI Struct layout.
5
+ #
6
+ # Given the @@@ portion in:
7
+ #
8
+ # module Zlib::ZStream < FFI::Struct
9
+ # @@@
10
+ # name "struct z_stream_s"
11
+ # include "zlib.h"
12
+ #
13
+ # field :next_in, :pointer
14
+ # field :avail_in, :uint
15
+ # field :total_in, :ulong
16
+ #
17
+ # # ...
18
+ # @@@
19
+ # end
20
+ #
21
+ # Structures will create the layout:
22
+ #
23
+ # layout :next_in, :pointer, 0,
24
+ # :avail_in, :uint, 4,
25
+ # :total_in, :ulong, 8,
26
+ # # ...
27
+ #
28
+ # StructGenerator does its best to pad the layout it produces to preserve
29
+ # line numbers. Place the struct definition as close to the top of the file
30
+ # for best results.
31
+
32
+ class Structures
33
+
34
+ ##
35
+ # A field in a Struct.
36
+
37
+ class Field
38
+
39
+ attr_reader :name
40
+ attr_reader :type
41
+ attr_reader :offset
42
+ attr_accessor :size
43
+
44
+ def initialize(name, type)
45
+ @name = name
46
+ @type = type
47
+ @offset = nil
48
+ @size = nil
49
+ end
50
+
51
+ def offset=(o)
52
+ @offset = o
53
+ end
54
+
55
+ def to_config(name)
56
+ buf = []
57
+ buf << "rbx.platform.#{name}.#{@name}.offset = #{@offset}"
58
+ buf << "rbx.platform.#{name}.#{@name}.size = #{@size}"
59
+ buf << "rbx.platform.#{name}.#{@name}.type = #{@type}" if @type
60
+ buf
61
+ end
62
+ end
63
+
64
+
65
+ attr_accessor :size
66
+ attr_reader :fields
67
+
68
+ def initialize(name)
69
+ @name = name
70
+ @struct_name = nil
71
+ @includes = []
72
+ @include_dirs = []
73
+ @fields = []
74
+ @found = false
75
+ @size = nil
76
+ @platform = Platform.new
77
+
78
+ if block_given? then
79
+ yield self
80
+ calculate
81
+ end
82
+ end
83
+
84
+ def source(io)
85
+ io.puts "#include <stdio.h>"
86
+
87
+ @includes.each do |inc|
88
+ io.puts "#include <#{inc}>"
89
+ end
90
+
91
+ io.puts "#include <stddef.h>\n\n"
92
+ io.puts "int main(int argc, char **argv)\n{"
93
+ io.puts " #{@struct_name} s;"
94
+ io.puts %[ printf("sizeof(#{@struct_name}) %u\\n", (unsigned int) sizeof(#{@struct_name}));]
95
+
96
+ @fields.each do |field|
97
+ io.puts <<-EOF
98
+ printf("#{field.name} %u %u\\n", (unsigned int) offsetof(#{@struct_name}, #{field.name}),
99
+ (unsigned int) sizeof(s.#{field.name}));
100
+ EOF
101
+ end
102
+
103
+ io.puts "\n return 0;\n}"
104
+ end
105
+
106
+ def prepare(name, target)
107
+ @platform.compile(@include_dirs, name, target)
108
+ end
109
+
110
+ def prepare_failed
111
+ "Compilation error generating struct #{@name} (#{@struct_name})"
112
+ end
113
+
114
+ def process(target)
115
+ target
116
+ end
117
+
118
+ def process_failed
119
+ "Error generating struct #{@name} (#{@struct_name})"
120
+ end
121
+
122
+ def calculate
123
+ raise "struct name not set" if @struct_name.nil?
124
+
125
+ output = BodyGuard.new(self, @struct_name, @platform).perform.split "\n"
126
+
127
+ sizeof = output.shift
128
+ unless @size
129
+ m = /\s*sizeof\([^)]+\) (\d+)/.match sizeof
130
+ @size = m[1]
131
+ end
132
+
133
+ line_no = 0
134
+ output.each do |line|
135
+ md = line.match(/.+ (\d+) (\d+)/)
136
+ @fields[line_no].offset = md[1].to_i
137
+ @fields[line_no].size = md[2].to_i
138
+
139
+ line_no += 1
140
+ end
141
+
142
+ @found = true
143
+ end
144
+
145
+ def field(name, type=nil)
146
+ field = Field.new(name, type)
147
+ @fields << field
148
+ return field
149
+ end
150
+
151
+ def found?
152
+ @found
153
+ end
154
+
155
+ def write_config(io)
156
+ io.puts "rbx.platform.#{@name}.sizeof = #{@size}"
157
+
158
+ @fields.each { |field| io.puts field.to_config(@name) }
159
+ end
160
+
161
+ def generate_layout
162
+ buf = ""
163
+
164
+ @fields.each_with_index do |field, i|
165
+ if buf.empty?
166
+ buf << "layout :#{field.name}, :#{field.type}, #{field.offset}"
167
+ else
168
+ buf << " :#{field.name}, :#{field.type}, #{field.offset}"
169
+ end
170
+
171
+ if i < @fields.length - 1
172
+ buf << ",\n"
173
+ end
174
+ end
175
+
176
+ buf
177
+ end
178
+
179
+ def get_field(name)
180
+ @fields.find { |f| name == f.name }
181
+ end
182
+
183
+ def include(i)
184
+ @includes << i
185
+ end
186
+
187
+ def include_dir(i)
188
+ @include_dirs << i
189
+ end
190
+
191
+ def name(n)
192
+ @struct_name = n
193
+ end
194
+ end
195
+ end
196
+
197
+ StructGenerator = Generators::Structures
198
+ end
@@ -0,0 +1,142 @@
1
+ module FFI
2
+ module Generators
3
+ class Types
4
+
5
+ ##
6
+ # Maps different C types to the C type representations we use
7
+
8
+ TYPE_MAP = {
9
+ "char" => :char,
10
+ "signed char" => :char,
11
+ "__signed char" => :char,
12
+ "unsigned char" => :uchar,
13
+
14
+ "short" => :short,
15
+ "signed short" => :short,
16
+ "signed short int" => :short,
17
+ "unsigned short" => :ushort,
18
+ "unsigned short int" => :ushort,
19
+
20
+ "int" => :int,
21
+ "signed int" => :int,
22
+ "unsigned int" => :uint,
23
+
24
+ "long" => :long,
25
+ "long int" => :long,
26
+ "signed long" => :long,
27
+ "signed long int" => :long,
28
+ "unsigned long" => :ulong,
29
+ "unsigned long int" => :ulong,
30
+ "long unsigned int" => :ulong,
31
+
32
+ "long long" => :long_long,
33
+ "long long int" => :long_long,
34
+ "signed long long" => :long_long,
35
+ "signed long long int" => :long_long,
36
+ "unsigned long long" => :ulong_long,
37
+ "unsigned long long int" => :ulong_long,
38
+
39
+ "char *" => :string,
40
+ "void *" => :pointer,
41
+ }
42
+
43
+ def self.generate
44
+ new.generate
45
+ end
46
+
47
+ def initialize
48
+ @platform = Platform.new
49
+ end
50
+
51
+ def source(io)
52
+ io.puts "#include <stdint.h>"
53
+ io.puts "#include <sys/types.h>"
54
+ unless @platform.windows?
55
+ io.puts "#include <sys/socket.h>"
56
+ io.puts "#include <sys/resource.h>"
57
+ end
58
+ end
59
+
60
+ def prepare(name, target)
61
+ # we have nothing to do in this stage
62
+ end
63
+
64
+ def process(target)
65
+ "#{@platform.compiler} -E #{@platform.defines} #{target}"
66
+ end
67
+
68
+ def process_failed
69
+ "Error generating C types"
70
+ end
71
+
72
+ def generate
73
+ typedefs = BodyGuard.new(self, "ffi_types_generator", @platform).perform
74
+
75
+ code = ""
76
+
77
+ typedefs.split(/\n/).each do |type|
78
+ # We only care about single line typedef
79
+ next unless type =~ /typedef/
80
+ # Ignore unions or structs
81
+ next if type =~ /union|struct/
82
+
83
+ # strip off the starting typedef and ending ;
84
+ type.gsub!(/^(.*typedef\s*)/, "")
85
+ type.gsub!(/\s*;\s*$/, "")
86
+
87
+ parts = type.split(/\s+/)
88
+ def_type = parts.join(" ")
89
+
90
+ # GCC does mapping with __attribute__ stuf, also see
91
+ # http://hal.cs.berkeley.edu/cil/cil016.html section 16.2.7. Problem
92
+ # with this is that the __attribute__ stuff can either occur before or
93
+ # after the new type that is defined...
94
+ if type =~ /__attribute__/
95
+ if parts.last =~ /__QI__|__HI__|__SI__|__DI__|__word__/
96
+
97
+ # In this case, the new type is BEFORE __attribute__ we need to
98
+ # find the final_type as the type before the part that starts with
99
+ # __attribute__
100
+ final_type = ""
101
+ parts.each do |p|
102
+ break if p =~ /__attribute__/
103
+ final_type = p
104
+ end
105
+ else
106
+ final_type = parts.pop
107
+ end
108
+
109
+ def_type = case type
110
+ when /__QI__/ then "char"
111
+ when /__HI__/ then "short"
112
+ when /__SI__/ then "int"
113
+ when /__DI__/ then "long long"
114
+ when /__word__/ then "long"
115
+ else "int"
116
+ end
117
+
118
+ def_type = "unsigned #{def_type}" if type =~ /unsigned/
119
+ else
120
+ final_type = parts.pop
121
+ def_type = parts.join(" ")
122
+ end
123
+
124
+ if type = TYPE_MAP[def_type]
125
+ code << "rbx.platform.typedef.#{final_type} = #{type}\n"
126
+ TYPE_MAP[final_type] = TYPE_MAP[def_type]
127
+ else
128
+ # Fallback to an ordinary pointer if we don't know the type
129
+ if def_type =~ /\*/
130
+ code << "rbx.platform.typedef.#{final_type} = pointer\n"
131
+ TYPE_MAP[final_type] = :pointer
132
+ end
133
+ end
134
+ end
135
+
136
+ code
137
+ end
138
+ end
139
+ end
140
+
141
+ TypesGenerator = Generators::Types
142
+ end
@@ -0,0 +1,5 @@
1
+ module FFI
2
+ module Generators
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ffi2-generators
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Brian Shirai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Utilities for generating constants, types, and structs for FFI.
42
+ email:
43
+ - brixen@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - LICENSE
51
+ - README.md
52
+ - Rakefile
53
+ - ffi2-generators.gemspec
54
+ - lib/ffi2/generators.rb
55
+ - lib/ffi2/generators/constants.rb
56
+ - lib/ffi2/generators/file_processor.rb
57
+ - lib/ffi2/generators/structures.rb
58
+ - lib/ffi2/generators/types.rb
59
+ - lib/ffi2/generators/version.rb
60
+ homepage: https://github.com/rubinius/ffi2-generators
61
+ licenses:
62
+ - BSD
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.0.7
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: Utilities for generating constants, types, and structs for FFI.
84
+ test_files: []