yakg 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/Gemfile.lock +1 -1
  2. data/VERSION +1 -1
  3. data/lib/yakg.rb +2 -1
  4. data/vendor/gems/installit.sh +9 -5
  5. data/vendor/gems/ruby/1.8/gems/ffi-1.8.1/lib/ffi_c.bundle +0 -0
  6. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/CHANGELOG +12 -0
  7. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/LICENSE +8 -0
  8. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/README.md +40 -0
  9. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/array.rb +123 -0
  10. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/base.rb +197 -0
  11. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/boolean.rb +25 -0
  12. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/data.rb +42 -0
  13. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/date.rb +32 -0
  14. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/dictionary.rb +114 -0
  15. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/extensions.rb +158 -0
  16. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/null.rb +11 -0
  17. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/number.rb +98 -0
  18. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/string.rb +91 -0
  19. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation/version.rb +4 -0
  20. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/lib/corefoundation.rb +13 -0
  21. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/array_spec.rb +92 -0
  22. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/boolean_spec.rb +24 -0
  23. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/data_spec.rb +30 -0
  24. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/date_spec.rb +25 -0
  25. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/dictionary_spec.rb +81 -0
  26. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/extensions_spec.rb +127 -0
  27. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/null_spec.rb +7 -0
  28. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/number_spec.rb +52 -0
  29. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/spec_helper.rb +10 -0
  30. data/vendor/gems/ruby/1.9.1/gems/corefoundation-0.2.0/spec/string_spec.rb +48 -0
  31. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/.require_paths +2 -0
  32. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/COPYING +674 -0
  33. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/COPYING.LESSER +165 -0
  34. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/History.txt +1 -0
  35. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/LICENSE +14 -0
  36. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/README.md +109 -0
  37. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/Rakefile +219 -0
  38. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/ffi.gemspec +22 -0
  39. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/gen/Rakefile +30 -0
  40. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/gen/log +1 -0
  41. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/autopointer.rb +184 -0
  42. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/buffer.rb +4 -0
  43. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/callback.rb +4 -0
  44. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/enum.rb +162 -0
  45. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/errno.rb +33 -0
  46. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/ffi.iml +11 -0
  47. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/ffi.rb +33 -0
  48. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/io.rb +52 -0
  49. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/library.rb +489 -0
  50. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/managedstruct.rb +55 -0
  51. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/memorypointer.rb +1 -0
  52. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/arm-linux/types.conf +104 -0
  53. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i386-cygwin/types.conf +3 -0
  54. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i386-darwin/types.conf +100 -0
  55. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  56. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i386-linux/types.conf +103 -0
  57. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  58. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i386-openbsd/types.conf +126 -0
  59. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i386-solaris/types.conf +122 -0
  60. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i386-windows/types.conf +105 -0
  61. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/i486-gnu/types.conf +107 -0
  62. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/ia64-linux/types.conf +104 -0
  63. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/mips-linux/types.conf +102 -0
  64. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/mipsel-linux/types.conf +102 -0
  65. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/powerpc-aix/types.conf +180 -0
  66. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
  67. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/powerpc-linux/types.conf +100 -0
  68. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/s390-linux/types.conf +102 -0
  69. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/s390x-linux/types.conf +102 -0
  70. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/sparc-linux/types.conf +102 -0
  71. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/sparc-solaris/types.conf +128 -0
  72. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
  73. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/x86_64-darwin/types.conf +100 -0
  74. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
  75. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/x86_64-linux/types.conf +102 -0
  76. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/x86_64-netbsd/types.conf +126 -0
  77. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/x86_64-openbsd/types.conf +126 -0
  78. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
  79. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform/x86_64-windows/types.conf +27 -0
  80. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/platform.rb +139 -0
  81. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/pointer.rb +122 -0
  82. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/struct.rb +356 -0
  83. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/struct_layout_builder.rb +211 -0
  84. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/tools/const_generator.rb +229 -0
  85. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/tools/generator.rb +60 -0
  86. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/tools/generator_task.rb +36 -0
  87. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/tools/struct_generator.rb +194 -0
  88. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/tools/types_generator.rb +135 -0
  89. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/types.rb +177 -0
  90. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/union.rb +32 -0
  91. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/variadic.rb +65 -0
  92. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi/version.rb +4 -0
  93. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi.rb +28 -0
  94. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/lib/ffi_c.bundle +0 -0
  95. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/Benchmark.c +52 -0
  96. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/BoolTest.c +31 -0
  97. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/BufferTest.c +31 -0
  98. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/ClosureTest.c +190 -0
  99. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/EnumTest.c +34 -0
  100. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/FunctionTest.c +58 -0
  101. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/GNUmakefile +149 -0
  102. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/GlobalVariable.c +62 -0
  103. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/LastErrorTest.c +21 -0
  104. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/NumberTest.c +132 -0
  105. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/PointerTest.c +63 -0
  106. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/ReferenceTest.c +23 -0
  107. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/StringTest.c +34 -0
  108. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/StructTest.c +240 -0
  109. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/UnionTest.c +43 -0
  110. data/vendor/gems/ruby/1.9.1/gems/ffi-1.8.1/libtest/VariadicTest.c +62 -0
  111. data/vendor/gems/ruby/1.9.1/specifications/corefoundation-0.2.0.gemspec +44 -0
  112. data/vendor/gems/ruby/1.9.1/specifications/ffi-1.8.1.gemspec +43 -0
  113. metadata +172 -60
@@ -0,0 +1,229 @@
1
+ require 'tempfile'
2
+ require 'open3'
3
+
4
+ module FFI
5
+
6
+ # ConstGenerator turns C constants into ruby values.
7
+ #
8
+ # @example a simple example for stdio
9
+ # cg = FFI::ConstGenerator.new('stdio') do |gen|
10
+ # gen.const(:SEEK_SET)
11
+ # gen.const('SEEK_CUR')
12
+ # gen.const('seek_end') # this constant does not exist
13
+ # end # #calculate called automatically at the end of the block
14
+ #
15
+ # cg['SEEK_SET'] # => 0
16
+ # cg['SEEK_CUR'] # => 1
17
+ # cg['seek_end'] # => nil
18
+ # cg.to_ruby # => "SEEK_SET = 0\nSEEK_CUR = 1\n# seek_end not available"
19
+ class ConstGenerator
20
+ @options = {}
21
+ attr_reader :constants
22
+
23
+ # Creates a new constant generator that uses +prefix+ as a name, and an
24
+ # options hash.
25
+ #
26
+ # The only option is +:required+, which if set to +true+ raises an error if a
27
+ # constant you have requested was not found.
28
+ #
29
+ # @param [#to_s] prefix
30
+ # @param [Hash] options
31
+ # @return
32
+ # @option options [Boolean] :required
33
+ # @overload initialize(prefix, options)
34
+ # @overload initialize(prefix, options) { |gen| ... }
35
+ # @yieldparam [ConstGenerator] gen new generator is passed to the block
36
+ # When passed a block, {#calculate} is automatically called at the end of
37
+ # the block, otherwise you must call it yourself.
38
+ def initialize(prefix = nil, options = {})
39
+ @includes = ['stdio.h', 'stddef.h']
40
+ @constants = {}
41
+ @prefix = prefix
42
+
43
+ @required = options[:required]
44
+ @options = options
45
+
46
+ if block_given? then
47
+ yield self
48
+ calculate self.class.options.merge(options)
49
+ end
50
+ end
51
+ # Set class options
52
+ # These options are merged with {#initialize} options when it is called with a block.
53
+ # @param [Hash] options
54
+ # @return [Hash] class options
55
+ def self.options=(options)
56
+ @options = options
57
+ end
58
+ # Get class options.
59
+ # @return [Hash] class options
60
+ def self.options
61
+ @options
62
+ end
63
+ # @param [String] name
64
+ # @return constant value (converted if a +converter+ was defined).
65
+ # Access a constant by name.
66
+ def [](name)
67
+ @constants[name].converted_value
68
+ end
69
+
70
+ # Request the value for C constant +name+.
71
+ #
72
+ # @param [#to_s] name C constant name
73
+ # @param [String] format a printf format string to print the value out
74
+ # @param [String] cast a C cast for the value
75
+ # @param ruby_name alternate ruby name for {#to_ruby}
76
+ #
77
+ # @overload const(name, format=nil, cast='', ruby_name=nil, converter=nil)
78
+ # +converter+ is a Method or a Proc.
79
+ # @param [#call] converter convert the value from a string to the appropriate
80
+ # type for {#to_ruby}.
81
+ # @overload const(name, format=nil, cast='', ruby_name=nil) { |value| ... }
82
+ # Use a converter block. This block convert the value from a string to the
83
+ # appropriate type for {#to_ruby}.
84
+ # @yieldparam value constant value
85
+ def const(name, format = nil, cast = '', ruby_name = nil, converter = nil,
86
+ &converter_proc)
87
+ format ||= '%d'
88
+ cast ||= ''
89
+
90
+ if converter_proc and converter then
91
+ raise ArgumentError, "Supply only converter or converter block"
92
+ end
93
+
94
+ converter = converter_proc if converter.nil?
95
+
96
+ const = Constant.new name, format, cast, ruby_name, converter
97
+ @constants[name.to_s] = const
98
+ return const
99
+ end
100
+
101
+ # Calculate constants values.
102
+ # @param [Hash] options
103
+ # @option options [String] :cppflags flags for C compiler
104
+ # @return [nil]
105
+ # @raise if a constant is missing and +:required+ was set to +true+ (see {#initialize})
106
+ def calculate(options = {})
107
+ binary = File.join Dir.tmpdir, "rb_const_gen_bin_#{Process.pid}"
108
+
109
+ Tempfile.open("#{@prefix}.const_generator") do |f|
110
+ @includes.each do |inc|
111
+ f.puts "#include <#{inc}>"
112
+ end
113
+ f.puts "\nint main(int argc, char **argv)\n{"
114
+
115
+ @constants.each_value do |const|
116
+ f.puts <<-EOF
117
+ #ifdef #{const.name}
118
+ printf("#{const.name} #{const.format}\\n", #{const.cast}#{const.name});
119
+ #endif
120
+ EOF
121
+ end
122
+
123
+ f.puts "\n\treturn 0;\n}"
124
+ f.flush
125
+
126
+ output = `gcc #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -x c -Wall -Werror #{f.path} -o #{binary} 2>&1`
127
+
128
+ unless $?.success? then
129
+ output = output.split("\n").map { |l| "\t#{l}" }.join "\n"
130
+ raise "Compilation error generating constants #{@prefix}:\n#{output}"
131
+ end
132
+ end
133
+
134
+ output = `#{binary}`
135
+ File.unlink(binary + (FFI::Platform.windows? ? ".exe" : ""))
136
+ output.each_line do |line|
137
+ line =~ /^(\S+)\s(.*)$/
138
+ const = @constants[$1]
139
+ const.value = $2
140
+ end
141
+
142
+ missing_constants = @constants.select do |name, constant|
143
+ constant.value.nil?
144
+ end.map { |name,| name }
145
+
146
+ if @required and not missing_constants.empty? then
147
+ raise "Missing required constants for #{@prefix}: #{missing_constants.join ', '}"
148
+ end
149
+ end
150
+
151
+ # Dump constants to +io+.
152
+ # @param [#puts] io
153
+ # @return [nil]
154
+ def dump_constants(io)
155
+ @constants.each do |name, constant|
156
+ name = [@prefix, name].join '.' if @prefix
157
+ io.puts "#{name} = #{constant.converted_value}"
158
+ end
159
+ end
160
+
161
+ # Outputs values for discovered constants. If the constant's value was
162
+ # not discovered it is not omitted.
163
+ # @return [String]
164
+ def to_ruby
165
+ @constants.sort_by { |name,| name }.map do |name, constant|
166
+ if constant.value.nil? then
167
+ "# #{name} not available"
168
+ else
169
+ constant.to_ruby
170
+ end
171
+ end.join "\n"
172
+ end
173
+
174
+ # Add additional C include file(s) to calculate constants from.
175
+ # @note +stdio.h+ and +stddef.h+ automatically included
176
+ # @param [List<String>, Array<String>] i include file(s)
177
+ # @return [Array<String>] array of include files
178
+ def include(*i)
179
+ @includes |= i.flatten
180
+ end
181
+
182
+ end
183
+
184
+ # This class hold constants for {ConstGenerator}
185
+ class ConstGenerator::Constant
186
+
187
+ attr_reader :name, :format, :cast
188
+ attr_accessor :value
189
+
190
+ # @param [#to_s] name
191
+ # @param [String] format a printf format string to print the value out
192
+ # @param [String] cast a C cast for the value
193
+ # @param ruby_name alternate ruby name for {#to_ruby}
194
+ # @param [#call] converter convert the value from a string to the appropriate
195
+ # type for {#to_ruby}.
196
+ def initialize(name, format, cast, ruby_name = nil, converter=nil)
197
+ @name = name
198
+ @format = format
199
+ @cast = cast
200
+ @ruby_name = ruby_name
201
+ @converter = converter
202
+ @value = nil
203
+ end
204
+
205
+ # Return constant value (converted if a +converter+ was defined).
206
+ # @return constant value.
207
+ def converted_value
208
+ if @converter
209
+ @converter.call(@value)
210
+ else
211
+ @value
212
+ end
213
+ end
214
+
215
+ # get constant ruby name
216
+ # @return [String]
217
+ def ruby_name
218
+ @ruby_name || @name
219
+ end
220
+
221
+ # Get an evaluable string from constant.
222
+ # @return [String]
223
+ def to_ruby
224
+ "#{ruby_name} = #{converted_value}"
225
+ end
226
+
227
+ end
228
+
229
+ end
@@ -0,0 +1,60 @@
1
+ module FFI
2
+
3
+ # @private
4
+ class Generator
5
+
6
+ def initialize(ffi_name, rb_name, options = {})
7
+ @ffi_name = ffi_name
8
+ @rb_name = rb_name
9
+ @options = options
10
+ @name = File.basename rb_name, '.rb'
11
+
12
+ file = File.read @ffi_name
13
+
14
+ new_file = file.gsub(/^( *)@@@(.*?)@@@/m) do
15
+ @constants = []
16
+ @structs = []
17
+
18
+ indent = $1
19
+ original_lines = $2.count "\n"
20
+
21
+ instance_eval $2, @ffi_name, $`.count("\n")
22
+
23
+ new_lines = []
24
+ @constants.each { |c| new_lines << c.to_ruby }
25
+ @structs.each { |s| new_lines << s.generate_layout }
26
+
27
+ new_lines = new_lines.join("\n").split "\n" # expand multiline blocks
28
+ new_lines = new_lines.map { |line| indent + line }
29
+
30
+ padding = original_lines - new_lines.length
31
+ new_lines += [nil] * padding if padding >= 0
32
+
33
+ new_lines.join "\n"
34
+ end
35
+
36
+ open @rb_name, 'w' do |f|
37
+ f.puts "# This file is generated by rake. Do not edit."
38
+ f.puts
39
+ f.puts new_file
40
+ end
41
+ end
42
+
43
+ def constants(options = {}, &block)
44
+ @constants << FFI::ConstGenerator.new(@name, @options.merge(options), &block)
45
+ end
46
+
47
+ def struct(options = {}, &block)
48
+ @structs << FFI::StructGenerator.new(@name, @options.merge(options), &block)
49
+ end
50
+
51
+ ##
52
+ # Utility converter for constants
53
+
54
+ def to_s
55
+ proc { |obj| obj.to_s.inspect }
56
+ end
57
+
58
+ end
59
+ end
60
+
@@ -0,0 +1,36 @@
1
+ begin
2
+ require 'ffi/struct_generator'
3
+ require 'ffi/const_generator'
4
+ require 'ffi/generator'
5
+ rescue LoadError
6
+ # from Rakefile
7
+ require 'lib/ffi/struct_generator'
8
+ require 'lib/ffi/const_generator'
9
+ require 'lib/ffi/generator'
10
+ end
11
+
12
+ require 'rake'
13
+ require 'rake/tasklib'
14
+ require 'tempfile'
15
+
16
+ ##
17
+ # Rake task that calculates C structs for FFI::Struct.
18
+
19
+ # @private
20
+ class FFI::Generator::Task < Rake::TaskLib
21
+
22
+ def initialize(rb_names)
23
+ task :clean do rm_f rb_names end
24
+
25
+ rb_names.each do |rb_name|
26
+ ffi_name = "#{rb_name}.ffi"
27
+
28
+ file rb_name => ffi_name do |t|
29
+ puts "Generating #{rb_name}..." if Rake.application.options.trace
30
+
31
+ FFI::Generator.new ffi_name, rb_name
32
+ end
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,194 @@
1
+ require 'tempfile'
2
+
3
+ module FFI
4
+
5
+ ##
6
+ # Generates an FFI Struct layout.
7
+ #
8
+ # Given the @@@ portion in:
9
+ #
10
+ # module Zlib::ZStream < FFI::Struct
11
+ # @@@
12
+ # name "struct z_stream_s"
13
+ # include "zlib.h"
14
+ #
15
+ # field :next_in, :pointer
16
+ # field :avail_in, :uint
17
+ # field :total_in, :ulong
18
+ #
19
+ # # ...
20
+ # @@@
21
+ # end
22
+ #
23
+ # StructGenerator will create the layout:
24
+ #
25
+ # layout :next_in, :pointer, 0,
26
+ # :avail_in, :uint, 4,
27
+ # :total_in, :ulong, 8,
28
+ # # ...
29
+ #
30
+ # StructGenerator does its best to pad the layout it produces to preserve
31
+ # line numbers. Place the struct definition as close to the top of the file
32
+ # for best results.
33
+
34
+ class StructGenerator
35
+ @options = {}
36
+ attr_accessor :size
37
+ attr_reader :fields
38
+
39
+ def initialize(name, options = {})
40
+ @name = name
41
+ @struct_name = nil
42
+ @includes = []
43
+ @fields = []
44
+ @found = false
45
+ @size = nil
46
+
47
+ if block_given? then
48
+ yield self
49
+ calculate self.class.options.merge(options)
50
+ end
51
+ end
52
+ def self.options=(options)
53
+ @options = options
54
+ end
55
+ def self.options
56
+ @options
57
+ end
58
+ def calculate(options = {})
59
+ binary = File.join Dir.tmpdir, "rb_struct_gen_bin_#{Process.pid}"
60
+
61
+ raise "struct name not set" if @struct_name.nil?
62
+
63
+ Tempfile.open("#{@name}.struct_generator") do |f|
64
+ f.puts "#include <stdio.h>"
65
+
66
+ @includes.each do |inc|
67
+ f.puts "#include <#{inc}>"
68
+ end
69
+
70
+ f.puts "#include <stddef.h>\n\n"
71
+ f.puts "int main(int argc, char **argv)\n{"
72
+ f.puts " #{@struct_name} s;"
73
+ f.puts %[ printf("sizeof(#{@struct_name}) %u\\n", (unsigned int) sizeof(#{@struct_name}));]
74
+
75
+ @fields.each do |field|
76
+ f.puts <<-EOF
77
+ printf("#{field.name} %u %u\\n", (unsigned int) offsetof(#{@struct_name}, #{field.name}),
78
+ (unsigned int) sizeof(s.#{field.name}));
79
+ EOF
80
+ end
81
+
82
+ f.puts "\n return 0;\n}"
83
+ f.flush
84
+
85
+ output = `gcc #{options[:cppflags]} #{options[: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`
86
+
87
+ unless $?.success? then
88
+ @found = false
89
+ output = output.split("\n").map { |l| "\t#{l}" }.join "\n"
90
+ raise "Compilation error generating struct #{@name} (#{@struct_name}):\n#{output}"
91
+ end
92
+ end
93
+
94
+ output = `#{binary}`.split "\n"
95
+ File.unlink(binary + (FFI::Platform.windows? ? ".exe" : ""))
96
+ sizeof = output.shift
97
+ unless @size
98
+ m = /\s*sizeof\([^)]+\) (\d+)/.match sizeof
99
+ @size = m[1]
100
+ end
101
+
102
+ line_no = 0
103
+ output.each do |line|
104
+ md = line.match(/.+ (\d+) (\d+)/)
105
+ @fields[line_no].offset = md[1].to_i
106
+ @fields[line_no].size = md[2].to_i
107
+
108
+ line_no += 1
109
+ end
110
+
111
+ @found = true
112
+ end
113
+
114
+ def field(name, type=nil)
115
+ field = Field.new(name, type)
116
+ @fields << field
117
+ return field
118
+ end
119
+
120
+ def found?
121
+ @found
122
+ end
123
+
124
+ def dump_config(io)
125
+ io.puts "rbx.platform.#{@name}.sizeof = #{@size}"
126
+
127
+ @fields.each { |field| io.puts field.to_config(@name) }
128
+ end
129
+
130
+ def generate_layout
131
+ buf = ""
132
+
133
+ @fields.each_with_index do |field, i|
134
+ if buf.empty?
135
+ buf << "layout :#{field.name}, :#{field.type}, #{field.offset}"
136
+ else
137
+ buf << " :#{field.name}, :#{field.type}, #{field.offset}"
138
+ end
139
+
140
+ if i < @fields.length - 1
141
+ buf << ",\n"
142
+ end
143
+ end
144
+
145
+ buf
146
+ end
147
+
148
+ def get_field(name)
149
+ @fields.find { |f| name == f.name }
150
+ end
151
+
152
+ def include(i)
153
+ @includes << i
154
+ end
155
+
156
+ def name(n)
157
+ @struct_name = n
158
+ end
159
+
160
+ end
161
+
162
+ ##
163
+ # A field in a Struct.
164
+
165
+ class StructGenerator::Field
166
+
167
+ attr_reader :name
168
+ attr_reader :type
169
+ attr_reader :offset
170
+ attr_accessor :size
171
+
172
+ def initialize(name, type)
173
+ @name = name
174
+ @type = type
175
+ @offset = nil
176
+ @size = nil
177
+ end
178
+
179
+ def offset=(o)
180
+ @offset = o
181
+ end
182
+
183
+ def to_config(name)
184
+ buf = []
185
+ buf << "rbx.platform.#{name}.#{@name}.offset = #{@offset}"
186
+ buf << "rbx.platform.#{name}.#{@name}.size = #{@size}"
187
+ buf << "rbx.platform.#{name}.#{@name}.type = #{@type}" if @type
188
+ buf
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+
@@ -0,0 +1,135 @@
1
+ require 'tempfile'
2
+
3
+ module FFI
4
+
5
+ # @private
6
+ class TypesGenerator
7
+
8
+ ##
9
+ # Maps different C types to the C type representations we use
10
+
11
+ TYPE_MAP = {
12
+ "char" => :char,
13
+ "signed char" => :char,
14
+ "__signed char" => :char,
15
+ "unsigned char" => :uchar,
16
+
17
+ "short" => :short,
18
+ "signed short" => :short,
19
+ "signed short int" => :short,
20
+ "unsigned short" => :ushort,
21
+ "unsigned short int" => :ushort,
22
+
23
+ "int" => :int,
24
+ "signed int" => :int,
25
+ "unsigned int" => :uint,
26
+
27
+ "long" => :long,
28
+ "long int" => :long,
29
+ "signed long" => :long,
30
+ "signed long int" => :long,
31
+ "unsigned long" => :ulong,
32
+ "unsigned long int" => :ulong,
33
+ "long unsigned int" => :ulong,
34
+
35
+ "long long" => :long_long,
36
+ "long long int" => :long_long,
37
+ "signed long long" => :long_long,
38
+ "signed long long int" => :long_long,
39
+ "unsigned long long" => :ulong_long,
40
+ "unsigned long long int" => :ulong_long,
41
+
42
+ "char *" => :string,
43
+ "void *" => :pointer,
44
+ }
45
+
46
+ def self.generate(options = {})
47
+ typedefs = nil
48
+ Tempfile.open 'ffi_types_generator' do |io|
49
+ io.puts <<-C
50
+ #include <sys/types.h>
51
+ #if !(defined(WIN32))
52
+ #include <sys/socket.h>
53
+ #include <sys/resource.h>
54
+ #endif
55
+ C
56
+
57
+ io.close
58
+ cc = ENV['CC'] || 'gcc'
59
+ cmd = "#{cc} -E -x c #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -c"
60
+ if options[:input]
61
+ typedefs = File.read(options[:input])
62
+ elsif options[:remote]
63
+ typedefs = `ssh #{options[:remote]} #{cmd} - < #{io.path}`
64
+ else
65
+ typedefs = `#{cmd} #{io.path}`
66
+ end
67
+ end
68
+
69
+ code = ""
70
+
71
+ typedefs.each_line do |type|
72
+ # We only care about single line typedef
73
+ next unless type =~ /typedef/
74
+ # Ignore unions or structs
75
+ next if type =~ /union|struct/
76
+
77
+ # strip off the starting typedef and ending ;
78
+ type.gsub!(/^(.*typedef\s*)/, "")
79
+ type.gsub!(/\s*;\s*$/, "")
80
+
81
+ parts = type.split(/\s+/)
82
+ def_type = parts.join(" ")
83
+
84
+ # GCC does mapping with __attribute__ stuf, also see
85
+ # http://hal.cs.berkeley.edu/cil/cil016.html section 16.2.7. Problem
86
+ # with this is that the __attribute__ stuff can either occur before or
87
+ # after the new type that is defined...
88
+ if type =~ /__attribute__/
89
+ if parts.last =~ /__QI__|__HI__|__SI__|__DI__|__word__/
90
+
91
+ # In this case, the new type is BEFORE __attribute__ we need to
92
+ # find the final_type as the type before the part that starts with
93
+ # __attribute__
94
+ final_type = ""
95
+ parts.each do |p|
96
+ break if p =~ /__attribute__/
97
+ final_type = p
98
+ end
99
+ else
100
+ final_type = parts.pop
101
+ end
102
+
103
+ def_type = case type
104
+ when /__QI__/ then "char"
105
+ when /__HI__/ then "short"
106
+ when /__SI__/ then "int"
107
+ when /__DI__/ then "long long"
108
+ when /__word__/ then "long"
109
+ else "int"
110
+ end
111
+
112
+ def_type = "unsigned #{def_type}" if type =~ /unsigned/
113
+ else
114
+ final_type = parts.pop
115
+ def_type = parts.join(" ")
116
+ end
117
+
118
+ if type = TYPE_MAP[def_type]
119
+ code << "rbx.platform.typedef.#{final_type} = #{type}\n"
120
+ TYPE_MAP[final_type] = TYPE_MAP[def_type]
121
+ else
122
+ # Fallback to an ordinary pointer if we don't know the type
123
+ if def_type =~ /\*/
124
+ code << "rbx.platform.typedef.#{final_type} = pointer\n"
125
+ TYPE_MAP[final_type] = :pointer
126
+ end
127
+ end
128
+ end
129
+
130
+ code
131
+ end
132
+
133
+ end
134
+ end
135
+