ffi-swig-generator 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.hg/branch.cache +2 -0
- data/.hg/dirstate +0 -0
- data/.hg/store/00changelog.i +0 -0
- data/.hg/store/00manifest.i +0 -0
- data/.hg/store/data/.hgignore.i +0 -0
- data/.hg/store/data/.hgtags.i +0 -0
- data/.hg/store/data/_history.txt.i +0 -0
- data/.hg/store/data/_r_e_a_d_m_e.rdoc.i +0 -0
- data/.hg/store/data/_rakefile.i +0 -0
- data/.hg/store/data/cucumber.yml.i +0 -0
- data/.hg/store/data/examples/_rakefile.i +0 -0
- data/.hg/store/data/features/generate.feature.i +0 -0
- data/.hg/store/data/features/step__definitions/generate.rb.i +0 -0
- data/.hg/store/data/features/support/env.rb.i +0 -0
- data/.hg/store/data/features/support/results.rb.i +0 -0
- data/.hg/store/data/features/support/templates.rb.i +0 -0
- data/.hg/store/data/lib/ffi-swig-generator.rb.i +0 -0
- data/.hg/store/data/lib/generator/application.rb.i +0 -0
- data/.hg/store/data/lib/generator/constant.rb.i +0 -0
- data/.hg/store/data/lib/generator/enum.rb.i +0 -0
- data/.hg/store/data/lib/generator/function.rb.i +0 -0
- data/.hg/store/data/lib/generator/generator.rb.i +0 -0
- data/.hg/store/data/lib/generator/generatortask.rb.i +0 -0
- data/.hg/store/data/lib/generator/logger.rb.i +0 -0
- data/.hg/store/data/lib/generator/node.rb.i +0 -0
- data/.hg/store/data/lib/generator/parser.rb.i +0 -0
- data/.hg/store/data/lib/generator/struct.rb.i +0 -0
- data/.hg/store/data/lib/generator/type.rb.i +0 -0
- data/.hg/store/data/lib/generator/types.rb.i +0 -0
- data/.hg/store/data/spec/generator/constant__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/enum__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/function__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/generator__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/node__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/parser__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/struct__spec.rb.i +0 -0
- data/.hg/store/data/spec/generator/swig/constants.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/functions.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/testlib.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/typedefs.i.i +0 -0
- data/.hg/store/data/spec/generator/swig/types.i.i +0 -0
- data/.hg/store/data/spec/generator/type__spec.rb.i +0 -0
- data/.hg/store/data/spec/spec__helper.rb.i +0 -0
- data/.hg/store/data/tasks/cucumber.rake.i +0 -0
- data/.hg/store/undo +0 -0
- data/.hg/undo.dirstate +0 -0
- data/.hgignore +3 -0
- data/.hgtags +1 -0
- data/History.txt +22 -2
- data/README.rdoc +26 -22
- data/Rakefile +2 -3
- data/cucumber.yml +1 -0
- data/examples/Rakefile +5 -3
- data/examples/generated/libc_wrap.rb +18 -0
- data/examples/generated/libc_wrap.xml +597 -0
- data/examples/generated/wiiuse_wrap.rb +322 -0
- data/examples/generated/wiiuse_wrap.xml +9025 -0
- data/features/generate.feature +45 -0
- data/features/step_definitions/generate.rb +32 -0
- data/features/support/env.rb +4 -0
- data/features/support/templates.rb +381 -0
- data/lib/ffi-swig-generator.rb +1 -1
- data/lib/generator/application.rb +1 -1
- data/lib/generator/constant.rb +24 -0
- data/lib/generator/enum.rb +38 -0
- data/lib/generator/function.rb +71 -0
- data/lib/generator/generatortask.rb +21 -9
- data/lib/generator/logger.rb +29 -0
- data/lib/generator/node.rb +19 -0
- data/lib/generator/parser.rb +168 -0
- data/lib/generator/struct.rb +76 -0
- data/lib/generator/type.rb +128 -0
- data/lib/generator/types.rb +36 -0
- data/spec/generator/constant_spec.rb +17 -0
- data/spec/generator/enum_spec.rb +29 -0
- data/spec/generator/function_spec.rb +66 -0
- data/spec/generator/parser_spec.rb +250 -0
- data/spec/generator/struct_spec.rb +77 -0
- data/spec/generator/swig/constants.i +5 -0
- data/spec/generator/swig/functions.i +8 -0
- data/spec/generator/swig/testlib.i +42 -0
- data/spec/generator/swig/typedefs.i +1 -0
- data/spec/generator/swig/types.i +1 -0
- data/spec/generator/type_spec.rb +38 -0
- data/spec/spec_helper.rb +6 -0
- data/tasks/cucumber.rake +8 -0
- metadata +58 -18
- data/lib/generator/generator.rb +0 -344
- data/spec/generator/generator_spec.rb +0 -248
@@ -0,0 +1,45 @@
|
|
1
|
+
Feature: Generate FFI glue code from SWIG interface.
|
2
|
+
|
3
|
+
In order to generate ruby-ffi glue code.
|
4
|
+
As a developer of ruby-ffi bindings.
|
5
|
+
I want the generator to automagically produce code for me.
|
6
|
+
|
7
|
+
Scenario: Generate code using default configuration
|
8
|
+
Given we are in a project directory
|
9
|
+
And the project directory is configured for the 'Scenario1'
|
10
|
+
When rake task 'ffi:generate' is invoked
|
11
|
+
Then rake task 'ffi:generate' succeeded
|
12
|
+
And the file 'generated/interface_wrap.rb' is created
|
13
|
+
And the file 'generated/interface_wrap.xml' is created
|
14
|
+
And the file 'generated/interface_wrap.rb' contains ffi glue code
|
15
|
+
And the tmp directory is removed
|
16
|
+
|
17
|
+
Scenario: Generate code using a configuration hash
|
18
|
+
Given we are in a project directory
|
19
|
+
And the project directory is configured for the 'Scenario2'
|
20
|
+
When rake task 'ffi:generate' is invoked
|
21
|
+
Then rake task 'ffi:generate' succeeded
|
22
|
+
And the file 'generated/interface_wrap.rb' is created
|
23
|
+
And the file 'generated/interface_wrap.xml' is created
|
24
|
+
And the file 'generated/interface_wrap.rb' contains ffi glue code
|
25
|
+
And the tmp directory is removed
|
26
|
+
|
27
|
+
Scenario: Generate code using a configuration block
|
28
|
+
Given we are in a project directory
|
29
|
+
And the project directory is configured for the 'Scenario3'
|
30
|
+
When rake task 'ffi:generate' is invoked
|
31
|
+
Then rake task 'ffi:generate' succeeded
|
32
|
+
And the file 'generated/interface_wrap.rb' is created
|
33
|
+
And the file 'generated/interface_wrap.xml' is created
|
34
|
+
And the file 'generated/interface_wrap.rb' contains ffi glue code
|
35
|
+
And the tmp directory is removed
|
36
|
+
|
37
|
+
Scenario: Generate code using a configuration file
|
38
|
+
Given we are in a project directory
|
39
|
+
And the project directory is configured for the 'Scenario4'
|
40
|
+
When rake task 'ffi:generate' is invoked
|
41
|
+
Then rake task 'ffi:generate' succeeded
|
42
|
+
And the file 'generated/interface_wrap.rb' is created
|
43
|
+
And the file 'generated/interface_wrap.xml' is created
|
44
|
+
And the file 'generated/interface_wrap.rb' contains ffi glue code
|
45
|
+
And the tmp directory is removed
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Given /^we are in a project directory$/ do
|
2
|
+
FileUtils.mkdir_p('tmp')
|
3
|
+
Dir.chdir('tmp')
|
4
|
+
end
|
5
|
+
|
6
|
+
Given /^the project directory is configured for the '(.+)'$/ do |mod|
|
7
|
+
@scenario = eval(mod)
|
8
|
+
@scenario.generate
|
9
|
+
end
|
10
|
+
|
11
|
+
When /^rake task 'ffi:generate' is invoked$/ do
|
12
|
+
@output = `rake ffi:generate 2>&1`
|
13
|
+
@result = $?.success?
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^rake task 'ffi:generate' succeeded$/ do
|
17
|
+
@result.should be_true
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^the file '(.+)' is created/ do |fn|
|
21
|
+
File.exists?(fn).should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^the file '(.+)' contains ffi glue code$/ do |fn|
|
25
|
+
File.read(fn).should == @scenario.result_template
|
26
|
+
end
|
27
|
+
|
28
|
+
Then /^the tmp directory is removed$/ do
|
29
|
+
Dir.chdir('..')
|
30
|
+
FileUtils.rm_rf 'tmp'
|
31
|
+
File.exists?('tmp').should be_false
|
32
|
+
end
|
@@ -0,0 +1,381 @@
|
|
1
|
+
class Scenario1
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def interface_dir
|
6
|
+
'.'
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_file(fn, &blk)
|
10
|
+
File.open(fn, 'w') do |file|
|
11
|
+
yield file
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate
|
16
|
+
FileUtils.mkdir interface_dir unless File.exists?(interface_dir)
|
17
|
+
create_file(File.join(interface_dir, 'interface.i')) { |file| file << interface_template }
|
18
|
+
create_file('Rakefile') { |file| file << rakefile_template }
|
19
|
+
end
|
20
|
+
|
21
|
+
def interface_template
|
22
|
+
<<-EOF
|
23
|
+
%module testlib
|
24
|
+
|
25
|
+
%{
|
26
|
+
module TestLib
|
27
|
+
extend FFI::Library
|
28
|
+
%}
|
29
|
+
|
30
|
+
#define CONST_1 0x10
|
31
|
+
#define CONST_2 0x20
|
32
|
+
|
33
|
+
typedef unsigned char byte;
|
34
|
+
typedef enum e_1 {
|
35
|
+
ENUM_1, ENUM_2, ENUM_3
|
36
|
+
} enum_t;
|
37
|
+
|
38
|
+
union union_t {
|
39
|
+
char c;
|
40
|
+
float f;
|
41
|
+
};
|
42
|
+
|
43
|
+
struct test_struct {
|
44
|
+
int i;
|
45
|
+
char c;
|
46
|
+
byte b;
|
47
|
+
};
|
48
|
+
|
49
|
+
struct CamelCaseStruct {
|
50
|
+
int i;
|
51
|
+
char c;
|
52
|
+
byte b;
|
53
|
+
};
|
54
|
+
|
55
|
+
typedef struct {
|
56
|
+
char c;
|
57
|
+
} test_struct_3;
|
58
|
+
|
59
|
+
typedef void (*cb)(char*, char*);
|
60
|
+
typedef void * (*cb_2)(char*, const char *);
|
61
|
+
typedef CamelCaseStruct (*cb_3)(char*, CamelCaseStruct);
|
62
|
+
|
63
|
+
struct test_struct_2 {
|
64
|
+
struct test_struct s;
|
65
|
+
CamelCaseStruct camel_case_struct;
|
66
|
+
test_struct_3 s_3;
|
67
|
+
enum_t e;
|
68
|
+
cb func;
|
69
|
+
union_t u;
|
70
|
+
cb callback;
|
71
|
+
void (*inline_callback)();
|
72
|
+
};
|
73
|
+
|
74
|
+
// struct with getter/setter method for strings and callbacks
|
75
|
+
|
76
|
+
struct _test_struct_4 {
|
77
|
+
char* string;
|
78
|
+
void (*inline_callback)();
|
79
|
+
};
|
80
|
+
|
81
|
+
struct test_struct_5 {
|
82
|
+
int i;
|
83
|
+
union {
|
84
|
+
struct {
|
85
|
+
int a;
|
86
|
+
int b;
|
87
|
+
} nested_struct_field_1;
|
88
|
+
struct {
|
89
|
+
int c;
|
90
|
+
int d;
|
91
|
+
} nested_struct_field_2;
|
92
|
+
struct {
|
93
|
+
int e;
|
94
|
+
int f;
|
95
|
+
} nested_struct_field_3;
|
96
|
+
union {
|
97
|
+
long l;
|
98
|
+
long long ll;
|
99
|
+
} union_field;
|
100
|
+
float f;
|
101
|
+
} big_union_field;
|
102
|
+
char c;
|
103
|
+
};
|
104
|
+
|
105
|
+
int get_int(struct test_struct* s);
|
106
|
+
char get_char(struct test_struct* s);
|
107
|
+
int func_with_enum(enum e_1 e);
|
108
|
+
int func_with_enum_2(enum_t e);
|
109
|
+
byte func_with_typedef();
|
110
|
+
%{
|
111
|
+
end
|
112
|
+
%}
|
113
|
+
EOF
|
114
|
+
end
|
115
|
+
|
116
|
+
def result_template
|
117
|
+
<<-EOF
|
118
|
+
|
119
|
+
module TestLib
|
120
|
+
extend FFI::Library
|
121
|
+
CONST_1 = 0x10
|
122
|
+
CONST_2 = 0x20
|
123
|
+
ENUM_1 = 0
|
124
|
+
ENUM_2 = 1
|
125
|
+
ENUM_3 = 2
|
126
|
+
|
127
|
+
class UnionT < FFI::Union
|
128
|
+
layout(
|
129
|
+
:c, :char,
|
130
|
+
:f, :float
|
131
|
+
)
|
132
|
+
end
|
133
|
+
class TestStruct < FFI::Struct
|
134
|
+
layout(
|
135
|
+
:i, :int,
|
136
|
+
:c, :char,
|
137
|
+
:b, :uchar
|
138
|
+
)
|
139
|
+
end
|
140
|
+
class CamelCaseStruct < FFI::Struct
|
141
|
+
layout(
|
142
|
+
:i, :int,
|
143
|
+
:c, :char,
|
144
|
+
:b, :uchar
|
145
|
+
)
|
146
|
+
end
|
147
|
+
class TestStruct3 < FFI::Struct
|
148
|
+
layout(
|
149
|
+
:c, :char
|
150
|
+
)
|
151
|
+
end
|
152
|
+
callback(:cb, [ :string, :string ], :void)
|
153
|
+
callback(:cb_2, [ :string, :string ], :pointer)
|
154
|
+
callback(:cb_3, [ :string, CamelCaseStruct ], CamelCaseStruct)
|
155
|
+
class TestStruct2 < FFI::Struct
|
156
|
+
layout(
|
157
|
+
:s, TestStruct,
|
158
|
+
:camel_case_struct, CamelCaseStruct,
|
159
|
+
:s_3, TestStruct3,
|
160
|
+
:e, :int,
|
161
|
+
:func, :cb,
|
162
|
+
:u, UnionT,
|
163
|
+
:callback, :cb,
|
164
|
+
:inline_callback, callback([ ], :void)
|
165
|
+
)
|
166
|
+
def func=(cb)
|
167
|
+
@func = cb
|
168
|
+
self[:func] = @func
|
169
|
+
end
|
170
|
+
def func
|
171
|
+
@func
|
172
|
+
end
|
173
|
+
def callback=(cb)
|
174
|
+
@callback = cb
|
175
|
+
self[:callback] = @callback
|
176
|
+
end
|
177
|
+
def callback
|
178
|
+
@callback
|
179
|
+
end
|
180
|
+
def inline_callback=(cb)
|
181
|
+
@inline_callback = cb
|
182
|
+
self[:inline_callback] = @inline_callback
|
183
|
+
end
|
184
|
+
def inline_callback
|
185
|
+
@inline_callback
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
class TestStruct4 < FFI::Struct
|
190
|
+
layout(
|
191
|
+
:string, :pointer,
|
192
|
+
:inline_callback, callback([ ], :void)
|
193
|
+
)
|
194
|
+
def string=(str)
|
195
|
+
@string = FFI::MemoryPointer.from_string(str)
|
196
|
+
self[:string] = @string
|
197
|
+
end
|
198
|
+
def string
|
199
|
+
@string.get_string(0)
|
200
|
+
end
|
201
|
+
def inline_callback=(cb)
|
202
|
+
@inline_callback = cb
|
203
|
+
self[:inline_callback] = @inline_callback
|
204
|
+
end
|
205
|
+
def inline_callback
|
206
|
+
@inline_callback
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
class TestStruct5BigUnionFieldNestedStructField1 < FFI::Struct
|
211
|
+
layout(
|
212
|
+
:a, :int,
|
213
|
+
:b, :int
|
214
|
+
)
|
215
|
+
end
|
216
|
+
class TestStruct5BigUnionFieldNestedStructField2 < FFI::Struct
|
217
|
+
layout(
|
218
|
+
:c, :int,
|
219
|
+
:d, :int
|
220
|
+
)
|
221
|
+
end
|
222
|
+
class TestStruct5BigUnionFieldNestedStructField3 < FFI::Struct
|
223
|
+
layout(
|
224
|
+
:e, :int,
|
225
|
+
:f, :int
|
226
|
+
)
|
227
|
+
end
|
228
|
+
class TestStruct5BigUnionFieldUnionField < FFI::Union
|
229
|
+
layout(
|
230
|
+
:l, :long,
|
231
|
+
:ll, :long_long
|
232
|
+
)
|
233
|
+
end
|
234
|
+
# FIXME: Nested structures are not correctly supported at the moment.
|
235
|
+
# Please check the order of the declarations in the structure below.
|
236
|
+
# class TestStruct5BigUnionField < FFI::Union
|
237
|
+
# layout(
|
238
|
+
# :f, :float,
|
239
|
+
# :union_field, TestStruct5BigUnionFieldUnionField,
|
240
|
+
# :nested_struct_field_3, TestStruct5BigUnionFieldNestedStructField3,
|
241
|
+
# :nested_struct_field_2, TestStruct5BigUnionFieldNestedStructField2,
|
242
|
+
# :nested_struct_field_1, TestStruct5BigUnionFieldNestedStructField1
|
243
|
+
# )
|
244
|
+
# end
|
245
|
+
# FIXME: Nested structures are not correctly supported at the moment.
|
246
|
+
# Please check the order of the declarations in the structure below.
|
247
|
+
# class TestStruct5 < FFI::Struct
|
248
|
+
# layout(
|
249
|
+
# :i, :int,
|
250
|
+
# :c, :char,
|
251
|
+
# :big_union_field, TestStruct5BigUnionField
|
252
|
+
# )
|
253
|
+
# end
|
254
|
+
attach_function :get_int, [ :pointer ], :int
|
255
|
+
attach_function :get_char, [ :pointer ], :char
|
256
|
+
attach_function :func_with_enum, [ :int ], :int
|
257
|
+
attach_function :func_with_enum_2, [ :int ], :int
|
258
|
+
attach_function :func_with_typedef, [ ], :uchar
|
259
|
+
|
260
|
+
end
|
261
|
+
EOF
|
262
|
+
end
|
263
|
+
|
264
|
+
def rakefile_template
|
265
|
+
<<-EOF
|
266
|
+
require '../lib/ffi-swig-generator'
|
267
|
+
|
268
|
+
FFI::Generator::Task.new
|
269
|
+
EOF
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
class Scenario2 < Scenario1
|
277
|
+
|
278
|
+
class << self
|
279
|
+
|
280
|
+
def interface_dir
|
281
|
+
'interfaces'
|
282
|
+
end
|
283
|
+
|
284
|
+
def rakefile_template
|
285
|
+
<<-EOF
|
286
|
+
require 'rubygems'
|
287
|
+
require '../lib/ffi-swig-generator'
|
288
|
+
|
289
|
+
FFI::Generator::Task.new :input_fn => 'interfaces/*.i', :output_dir => 'generated/'
|
290
|
+
|
291
|
+
EOF
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
class Scenario3 < Scenario2
|
299
|
+
|
300
|
+
class << self
|
301
|
+
|
302
|
+
def rakefile_template
|
303
|
+
<<-EOF
|
304
|
+
require 'rubygems'
|
305
|
+
require '../lib/ffi-swig-generator'
|
306
|
+
|
307
|
+
FFI::Generator::Task.new do |task|
|
308
|
+
task.input_fn = 'interfaces/*.i'
|
309
|
+
task.output_dir = 'generated/'
|
310
|
+
end
|
311
|
+
|
312
|
+
EOF
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
class Scenario4 < Scenario3
|
320
|
+
|
321
|
+
class << self
|
322
|
+
|
323
|
+
def generate
|
324
|
+
super
|
325
|
+
create_file(File.join(interface_dir, 'interface.rb')) { |file| file << config_template }
|
326
|
+
end
|
327
|
+
|
328
|
+
def rakefile_template
|
329
|
+
<<-EOF
|
330
|
+
require 'rubygems'
|
331
|
+
require '../lib/ffi-swig-generator'
|
332
|
+
|
333
|
+
FFI::Generator::Task.new do |task|
|
334
|
+
task.input_fn = 'interfaces/*.i'
|
335
|
+
task.output_dir = 'generated/'
|
336
|
+
end
|
337
|
+
|
338
|
+
EOF
|
339
|
+
end
|
340
|
+
|
341
|
+
def interface_template
|
342
|
+
<<-EOF
|
343
|
+
%module my_interface
|
344
|
+
|
345
|
+
#define CONST_1 0xff1;
|
346
|
+
#define CONST_2 0Xff2;
|
347
|
+
|
348
|
+
typedef struct {
|
349
|
+
char a;
|
350
|
+
char b;
|
351
|
+
} my_struct_1;
|
352
|
+
|
353
|
+
typedef struct {
|
354
|
+
char c;
|
355
|
+
char d;
|
356
|
+
} my_struct_2;
|
357
|
+
|
358
|
+
EOF
|
359
|
+
end
|
360
|
+
|
361
|
+
def result_template
|
362
|
+
<<-EOF
|
363
|
+
CONST_1 = 0xff1
|
364
|
+
class MyStruct1 < FFI::Struct
|
365
|
+
layout(
|
366
|
+
:a, :char,
|
367
|
+
:b, :char
|
368
|
+
)
|
369
|
+
end
|
370
|
+
EOF
|
371
|
+
end
|
372
|
+
|
373
|
+
def config_template
|
374
|
+
<<-EOF
|
375
|
+
ignore 'my_struct_2', 'CONST_2'
|
376
|
+
EOF
|
377
|
+
end
|
378
|
+
|
379
|
+
end
|
380
|
+
|
381
|
+
end
|