remogatto-ffi-swig-generator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ require 'rake/tasklib'
2
+
3
+ module FFI
4
+ module Generator
5
+ class Task < Rake::TaskLib
6
+ def initialize(options = {})
7
+ @options = { :input_fn => '*.i', :output_dir => 'generated/' }.merge(options)
8
+ namespace 'ffi' do
9
+ define_generate_task
10
+ define_clean_task
11
+ end
12
+ end
13
+ private
14
+ def define_file_task(fn, xml_fn, output_fn)
15
+ desc "Generate #{output_fn} from #{fn}"
16
+ file output_fn => fn do
17
+ mkdir_p @options[:output_dir], :verbose => false
18
+ puts "Generating #{xml_fn} from #{fn} using SWIG..."
19
+ `swig -xml #{xml_fn} #{fn}`
20
+ puts "Generating #{output_fn} from #{xml_fn}..."
21
+ File.open(output_fn, 'w') do |file|
22
+ file << Parser.generate(Nokogiri::XML(File.open(xml_fn)))
23
+ end
24
+ end
25
+ end
26
+ def define_file_tasks
27
+ Dir.glob(@options[:input_fn]).inject([]) do |output_fns, fn|
28
+ output_fn = File.join(@options[:output_dir], "#{File.basename(fn, '.i')}_wrap.rb")
29
+ xml_fn = File.join(@options[:output_dir], "#{File.basename(fn, '.i')}_wrap.xml")
30
+ define_file_task(fn, xml_fn, output_fn)
31
+ output_fns << output_fn
32
+ end
33
+ end
34
+ def define_generate_task
35
+ (task :generate => define_file_tasks).add_description('Generate all files')
36
+ end
37
+ def define_clean_task
38
+ desc 'Remove all generated files'
39
+ task :clean do
40
+ rm_rf @options[:output_dir] unless @options[:output_dir] == '.'
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe FFI::Generator do
5
+ end
6
+
7
+ # EOF
@@ -0,0 +1,248 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+
3
+ include FFI
4
+
5
+ share_examples_for "All specs" do
6
+ after :all do
7
+ remove_xml
8
+ end
9
+ end
10
+
11
+ describe Generator::Parser do
12
+ it_should_behave_like 'All specs'
13
+ before :all do
14
+ @node = generate_xml_wrap_from('testlib')
15
+ end
16
+ it 'should generate ruby ffi wrap code' do
17
+ Generator::Parser.generate(@node).should == <<EOC
18
+
19
+ module TestLib
20
+ extend FFI::Library
21
+ CONST_1 = 0x10
22
+ CONST_2 = 0x20
23
+ ENUM_1 = 0
24
+ ENUM_2 = 1
25
+ ENUM_3 = 2
26
+
27
+ class UnionT < FFI::Union
28
+ layout(
29
+ :c, :char,
30
+ :f, :float
31
+ )
32
+ end
33
+ class TestStruct < FFI::Struct
34
+ layout(
35
+ :i, :int,
36
+ :c, :char,
37
+ :b, :uchar
38
+ )
39
+ end
40
+ class TestStruct3 < FFI::Struct
41
+ layout(
42
+ :c, :char
43
+ )
44
+ end
45
+ callback(:cb, [ :string, :string ], :void)
46
+ class TestStruct2 < FFI::Struct
47
+ layout(
48
+ :s, TestStruct,
49
+ :s_3, TestStruct3,
50
+ :e, :int,
51
+ :func, :cb,
52
+ :u, UnionT
53
+ )
54
+ end
55
+ attach_function :get_int, [ :pointer ], :int
56
+ attach_function :get_char, [ :pointer ], :char
57
+ attach_function :func_with_enum, [ :int ], :int
58
+ attach_function :func_with_enum_2, [ :int ], :int
59
+ attach_function :func_with_typedef, [ ], :uchar
60
+
61
+ end
62
+ EOC
63
+ end
64
+ end
65
+
66
+ describe Generator::Constant do
67
+ it_should_behave_like 'All specs'
68
+ before :all do
69
+ @node = generate_xml_wrap_from('constants')
70
+ end
71
+ it 'should return a ruby constant assignment' do
72
+ Generator::Constant.new(:node => @node / 'constant').to_s.should == "CONST_1 = 0x10"
73
+ end
74
+ end
75
+
76
+ describe Generator::Enum do
77
+ before :all do
78
+ @node = generate_xml_wrap_from('enums')
79
+ end
80
+ it 'should generate constants' do
81
+ Generator::Enum.new(:node => (@node / 'enum')[0]).to_s.should == <<EOE
82
+ ENUM_1 = 0
83
+ ENUM_2 = 1
84
+ ENUM_3 = 2
85
+ EOE
86
+ end
87
+ it 'should generate constants starting from the latest assignment' do
88
+ Generator::Enum.new(:node => (@node / 'enum')[1]).to_s.should == <<EOE
89
+ ENUM_21 = 2
90
+ ENUM_22 = 3
91
+ ENUM_23 = 4
92
+ EOE
93
+ Generator::Enum.new(:node => (@node / 'enum')[2]).to_s.should == <<EOE
94
+ ENUM_31 = 0
95
+ ENUM_32 = 5
96
+ ENUM_33 = 6
97
+ EOE
98
+ end
99
+ end
100
+
101
+ describe Generator::Type do
102
+ it_should_behave_like 'All specs'
103
+ before :all do
104
+ @node = generate_xml_wrap_from('types')
105
+ end
106
+ it 'should generate string type' do
107
+ Generator::Type.new(:node => (@node / 'cdecl')[0]).to_s.should == ':string'
108
+ end
109
+ it 'should generate pointer type' do
110
+ Generator::Type.new(:node => (@node / 'cdecl')[1]).to_s.should == ':pointer'
111
+ Generator::Type.new(:node => (@node / 'cdecl')[2]).to_s.should == ':pointer'
112
+ end
113
+ it 'should generate array type' do
114
+ Generator::Type.new(:node => (@node / 'cdecl')[3]).to_s.should == '[:int, 5]'
115
+ Generator::Type.new(:node => (@node / 'cdecl')[4]).to_s.should == '[:string, 5]'
116
+ end
117
+ it 'should generate struct type' do
118
+ Generator::Type.new(:node => (@node / 'cdecl')[6]).to_s.should == 'TestStruct'
119
+ end
120
+ it 'should generate struct array type' do
121
+ Generator::Type.new(:node => (@node / 'cdecl')[7]).to_s.should == '[TestStruct, 5]'
122
+ end
123
+ it 'should generate enum array type' do
124
+ Generator::Type.new(:node => (@node / 'cdecl')[8]).to_s.should == '[:int, 5]'
125
+ end
126
+ it 'should generate const type' do
127
+ Generator::Type.new(:node => (@node / 'cdecl')[9]).to_s.should == ':int'
128
+ Generator::Type.new(:node => (@node / 'cdecl')[10]).to_s.should == ':string'
129
+ end
130
+ Generator::TYPES.sort.each_with_index do |type, i|
131
+ it "should generate #{type[0]} type" do
132
+ Generator::Type.new(:node => (@node / 'cdecl')[i + 11]).to_s.should == type[1]
133
+ end
134
+ end
135
+ end
136
+
137
+ describe Generator::Function do
138
+ it_should_behave_like 'All specs'
139
+ before :all do
140
+ @node = generate_xml_wrap_from('functions')
141
+ end
142
+ it 'should return a properly generated attach_method' do
143
+ Generator::Function.new(:node => (@node / 'cdecl')[0]).to_s.should == "attach_function :func_1, [ :char, :int ], :int"
144
+ end
145
+ it 'should properly generate pointer arguments' do
146
+ Generator::Function.new(:node => (@node / 'cdecl')[1]).to_s.should == "attach_function :func_2, [ :pointer, :pointer, :pointer ], :uint"
147
+ end
148
+ it 'should properly generate string arguments' do
149
+ Generator::Function.new(:node => (@node / 'cdecl')[2]).to_s.should == "attach_function :func_3, [ :string ], :void"
150
+ end
151
+ it 'should properly generate return type' do
152
+ Generator::Function.new(:node => (@node / 'cdecl')[3]).to_s.should == "attach_function :func_4, [ :int ], :string"
153
+ end
154
+ it 'should properly generate void return type' do
155
+ Generator::Function.new(:node => (@node / 'cdecl')[4]).to_s.should == "attach_function :func_5, [ ], :void"
156
+ end
157
+ it 'should properly generate pointer of pointer arguments' do
158
+ Generator::Function.new(:node => (@node / 'cdecl')[5]).to_s.should == "attach_function :func_6, [ :pointer ], :void"
159
+ end
160
+ it 'should properly generate enum arguments' do
161
+ Generator::Function.new(:node => (@node / 'cdecl')[6]).to_s.should == "attach_function :func_7, [ :int ], :void"
162
+ end
163
+ it 'should properly generate enum return type' do
164
+ Generator::Function.new(:node => (@node / 'cdecl')[7]).to_s.should == "attach_function :func_8, [ ], :int"
165
+ end
166
+ it 'should properly generate struct arguments' do
167
+ Generator::Function.new(:node => (@node / 'cdecl')[9]).to_s.should == "attach_function :func_9, [ TestStruct ], :void"
168
+ end
169
+ it 'should properly generate struct return type' do
170
+ Generator::Function.new(:node => (@node / 'cdecl')[10]).to_s.should == "attach_function :func_10, [ ], TestStruct"
171
+ end
172
+ it 'should properly generate a function with no parameters' do
173
+ Generator::Function.new(:node => (@node / 'cdecl')[11]).to_s.should == "attach_function :func_11, [ ], :void"
174
+ end
175
+ it 'should properly generate a function that takes a callback as argument' do
176
+ Generator::Function.new(:node => (@node / 'cdecl')[12]).to_s.should == "attach_function :func_12, [ callback(:callback, [ :float ], :void) ], :void"
177
+ Generator::Function.new(:node => (@node / 'cdecl')[13]).to_s.should == "attach_function :func_13, [ callback(:callback, [ :double, :float ], :int) ], :void"
178
+ Generator::Function.new(:node => (@node / 'cdecl')[14]).to_s.should == "attach_function :func_14, [ callback(:callback, [ :string ], :void) ], :void"
179
+ Generator::Function.new(:node => (@node / 'cdecl')[15]).to_s.should == "attach_function :func_15, [ callback(:callback, [ ], :void) ], :void"
180
+ end
181
+ end
182
+
183
+ describe Generator::Structure do
184
+ it_should_behave_like 'All specs'
185
+ before :all do
186
+ @node = generate_xml_wrap_from('structs')
187
+ end
188
+ it 'should properly generate the layout of a FFI::Struct class' do
189
+ Generator::Structure.new(:node => (@node / 'class')[0]).to_s.should == <<EOC
190
+ class TestStruct1 < FFI::Struct
191
+ layout(
192
+ :i, :int,
193
+ :c, :char,
194
+ :s, :string,
195
+ :a, [:char, 5]
196
+ )
197
+ end
198
+ EOC
199
+
200
+ end
201
+ it 'should properly generate the layout of a FFI::Struct containing pointer field' do
202
+ Generator::Structure.new(:node => (@node / 'class')[1]).to_s.should == <<EOC
203
+ class TestStruct2 < FFI::Struct
204
+ layout(
205
+ :ptr, :pointer
206
+ )
207
+ end
208
+ EOC
209
+ end
210
+ it 'should properly generate the layout of a FFI::Struct containing array field' do
211
+ Generator::Structure.new(:node => (@node / 'class')[2]).to_s.should == <<EOC
212
+ class TestStruct3 < FFI::Struct
213
+ layout(
214
+ :c, [:char, 5]
215
+ )
216
+ end
217
+ EOC
218
+
219
+ end
220
+ it 'should properly generate the layout of a FFI::Struct containing array field' do
221
+ Generator::Structure.new(:node => (@node / 'class')[3]).to_s.should == <<EOC
222
+ class TestStruct4 < FFI::Struct
223
+ layout(
224
+ :s, [TestStruct3, 5]
225
+ )
226
+ end
227
+ EOC
228
+
229
+ end
230
+ end
231
+
232
+ describe Generator::Union do
233
+ it_should_behave_like 'All specs'
234
+ before :all do
235
+ @node = generate_xml_wrap_from('unions')
236
+ end
237
+ it 'should properly generate the layout of a FFI::Union class' do
238
+ Generator::Union.new(:node => (@node / 'class')[0]).to_s.should == <<EOC
239
+ class UnionT < FFI::Union
240
+ layout(
241
+ :c, :char,
242
+ :f, :float
243
+ )
244
+ end
245
+ EOC
246
+ end
247
+ end
248
+
@@ -0,0 +1,3 @@
1
+ %module constant_wrap
2
+
3
+ #define CONST_1 0x10
@@ -0,0 +1,5 @@
1
+ %module enum_test
2
+
3
+ enum e { ENUM_1, ENUM_2, ENUM_3 };
4
+ enum e_2 { ENUM_21 = 2, ENUM_22, ENUM_23 };
5
+ enum e_3 { ENUM_31, ENUM_32 = 5, ENUM_33 };
@@ -0,0 +1,24 @@
1
+ %module function_testlib
2
+
3
+ int func_1(char c, int i);
4
+ unsigned int func_2(int* p1, int* p2, char** p3);
5
+ void func_3(char* str);
6
+ char *func_4(int i);
7
+ extern void func_5();
8
+ void func_6(void** ptr);
9
+ void func_7(enum e e1);
10
+ enum e { E_1, E_2 };
11
+ enum e func_8();
12
+ struct test_struct {
13
+ char c;
14
+ };
15
+ void func_9(struct test_struct s);
16
+ struct test_struct func_10();
17
+ void func_11(void);
18
+ void func_12(void (*callback)(float));
19
+ void func_13(int (*callback)(double, float));
20
+ void func_14(void (*callback)(char* str));
21
+ void func_15(void (*callback)(void));
22
+
23
+
24
+
@@ -0,0 +1,25 @@
1
+ %module test_struct
2
+
3
+ struct test_struct_1 {
4
+ int i;
5
+ char c;
6
+ const char* s;
7
+ const char a[5];
8
+ };
9
+
10
+ struct test_struct_2 {
11
+ int* ptr;
12
+ };
13
+
14
+ struct test_struct_3 {
15
+ char c[5];
16
+ };
17
+
18
+ struct test_struct_4 {
19
+ struct test_struct_3 s[5];
20
+ };
21
+
22
+ struct test_struct_5 {
23
+ struct test_struct_4 s;
24
+ };
25
+
@@ -0,0 +1,48 @@
1
+ %module testlib
2
+
3
+ %{
4
+ module TestLib
5
+ extend FFI::Library
6
+ %}
7
+
8
+ #define CONST_1 0x10
9
+ #define CONST_2 0x20
10
+
11
+ typedef unsigned char byte;
12
+ typedef enum e_1 {
13
+ ENUM_1, ENUM_2, ENUM_3
14
+ } enum_t;
15
+
16
+ union union_t {
17
+ char c;
18
+ float f;
19
+ };
20
+
21
+ struct test_struct {
22
+ int i;
23
+ char c;
24
+ byte b;
25
+ };
26
+
27
+ typedef struct {
28
+ char c;
29
+ } test_struct_3;
30
+
31
+ typedef void (*cb)(char*, char*);
32
+
33
+ struct test_struct_2 {
34
+ struct test_struct s;
35
+ test_struct_3 s_3;
36
+ enum_t e;
37
+ cb func;
38
+ union_t u;
39
+ };
40
+
41
+ int get_int(struct test_struct* s);
42
+ char get_char(struct test_struct* s);
43
+ int func_with_enum(enum e_1 e);
44
+ int func_with_enum_2(enum_t e);
45
+ byte func_with_typedef();
46
+ %{
47
+ end
48
+ %}
@@ -0,0 +1,5 @@
1
+ %module test_typedef
2
+
3
+ typedef unsigned char byte;
4
+ byte b;
5
+ typedef int *(PTF)(char*, char*)
@@ -0,0 +1,52 @@
1
+ %module types_test
2
+
3
+ char *string;
4
+ void *ptr;
5
+ char **ptr_2;
6
+
7
+ int array[5];
8
+ char* ptr_array[5];
9
+
10
+ struct test_struct {
11
+ char c;
12
+ };
13
+
14
+ enum e { E_1, E_2, E_3 };
15
+
16
+ struct test_struct ts;
17
+ struct test_struct a[5];
18
+ enum e enum_array[5];
19
+
20
+ const int ci;
21
+ const char* cstring;
22
+
23
+ char c;
24
+ double d;
25
+ float f;
26
+ int i;
27
+ long l;
28
+ long int li;
29
+ long long ll;
30
+ long long int lli;
31
+ long unsigned int lui;
32
+ short s;
33
+ signed char sc;
34
+ signed int si;
35
+ signed long sl;
36
+ signed long int sli;
37
+ signed long long sll;
38
+ signed long long int slli;
39
+ signed short ss;
40
+ signed short int ssi;
41
+ unsigned char uc;
42
+ unsigned int ui;
43
+ unsigned long ul;
44
+ unsigned long int uli;
45
+ unsigned long long ull;
46
+ unsigned long long int ulli;
47
+ unsigned short us;
48
+ unsigned short int usi;
49
+ void v;
50
+
51
+
52
+