rbind 0.0.2 → 0.0.3
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/lib/rbind.rb +1 -0
- data/lib/rbind/core/rbase.rb +5 -0
- data/lib/rbind/core/rclass.rb +4 -1
- data/lib/rbind/core/rdata_type.rb +14 -3
- data/lib/rbind/core/rnamespace.rb +57 -4
- data/lib/rbind/default_parser.rb +35 -12
- data/lib/rbind/generator_c.rb +48 -36
- data/lib/rbind/generator_extern.rb +39 -0
- data/lib/rbind/generator_ruby.rb +111 -55
- data/lib/rbind/rbind.rb +60 -3
- data/lib/rbind/templates/c/CMakeLists.txt +14 -1
- data/lib/rbind/templates/c/rbind.pc.in +11 -0
- data/lib/rbind/templates/c/type_conversion.cc +2 -6
- data/lib/rbind/templates/ruby/rbind.rb +2 -1
- data/lib/rbind/templates/ruby/rtype.rb +1 -1
- data/rbind.gemspec +2 -2
- metadata +4 -2
data/lib/rbind.rb
CHANGED
data/lib/rbind/core/rbase.rb
CHANGED
@@ -9,6 +9,7 @@ module Rbind
|
|
9
9
|
attr_accessor :version
|
10
10
|
attr_accessor :signature
|
11
11
|
attr_accessor :csignature
|
12
|
+
attr_accessor :ignore
|
12
13
|
|
13
14
|
class << self
|
14
15
|
attr_accessor :cprefix
|
@@ -76,6 +77,10 @@ module Rbind
|
|
76
77
|
["#{full_name}","#{cname}"]
|
77
78
|
end
|
78
79
|
|
80
|
+
def ignore?
|
81
|
+
!!@ignore
|
82
|
+
end
|
83
|
+
|
79
84
|
def signature(sig=nil)
|
80
85
|
return @signature || generate_signatures[0] unless sig
|
81
86
|
@signature = sig
|
data/lib/rbind/core/rclass.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
module Rbind
|
3
3
|
class RClass < RStruct
|
4
|
-
|
4
|
+
attr_reader :parent_classes
|
5
5
|
|
6
6
|
def initialize(name,*parent_classes)
|
7
7
|
@parent_classes = Hash.new
|
@@ -135,6 +135,9 @@ module Rbind
|
|
135
135
|
if @parent_classes.has_key? klass.name
|
136
136
|
raise ArgumentError,"#A parent class with the name #{klass.name} already exists"
|
137
137
|
end
|
138
|
+
if klass.full_name == full_name || klass == self
|
139
|
+
raise ArgumentError,"class #{klass.full_name} cannot be parent of its self"
|
140
|
+
end
|
138
141
|
# we have to disable the type check for the parent class
|
139
142
|
# otherwise derived types cannot be parsed
|
140
143
|
klass.check_type = false
|
@@ -4,13 +4,22 @@ module Rbind
|
|
4
4
|
attr_accessor :ptr,:ref
|
5
5
|
attr_accessor :typedef
|
6
6
|
attr_accessor :invalid_value
|
7
|
-
attr_accessor :cdelete_method
|
8
|
-
attr_accessor :check_type
|
7
|
+
attr_accessor :cdelete_method
|
8
|
+
attr_accessor :check_type
|
9
|
+
attr_accessor :extern_package_name
|
9
10
|
|
10
11
|
def initialize(name,*flags)
|
11
12
|
super
|
12
13
|
@invalid_value = 0
|
13
|
-
@
|
14
|
+
@check_type = true
|
15
|
+
end
|
16
|
+
|
17
|
+
def extern?
|
18
|
+
@flags.include? :Extern
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid_flags
|
22
|
+
super << :Extern
|
14
23
|
end
|
15
24
|
|
16
25
|
def ==(other)
|
@@ -54,10 +63,12 @@ module Rbind
|
|
54
63
|
!!@typedef
|
55
64
|
end
|
56
65
|
|
66
|
+
# elementar type of c
|
57
67
|
def basic_type?
|
58
68
|
true
|
59
69
|
end
|
60
70
|
|
71
|
+
# holds ofther operations, types or consts
|
61
72
|
def container?
|
62
73
|
false
|
63
74
|
end
|
@@ -4,7 +4,7 @@ module Rbind
|
|
4
4
|
class << self
|
5
5
|
attr_accessor :default_type_names
|
6
6
|
end
|
7
|
-
self.default_type_names = [:uint64,:int,:int64,:bool,:double,:float,:void,:char,:size_t]
|
7
|
+
self.default_type_names = [:uint64,:int,:int64,:bool,:double,:float,:void,:char,:size_t,:uint8_t]
|
8
8
|
|
9
9
|
attr_reader :operations
|
10
10
|
attr_reader :operation_alias
|
@@ -46,14 +46,22 @@ module Rbind
|
|
46
46
|
@used_namespaces[namespace.name] = namespace
|
47
47
|
end
|
48
48
|
|
49
|
-
def each_type(childs=true,&block)
|
49
|
+
def each_type(childs=true,all=false,&block)
|
50
50
|
if block_given?
|
51
51
|
types.each do |t|
|
52
|
+
next if !all && (t.ignore? || t.extern?)
|
52
53
|
yield t
|
53
|
-
t.each_type(
|
54
|
+
t.each_type(childs,all,&block) if childs && t.respond_to?(:each_type)
|
54
55
|
end
|
55
56
|
else
|
56
|
-
Enumerator.new(self,:each_type,childs)
|
57
|
+
Enumerator.new(self,:each_type,childs,all)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def each_container(all=false,&block)
|
62
|
+
each_type(true,all) do |t|
|
63
|
+
next unless t.container?
|
64
|
+
yield t
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
@@ -83,6 +91,51 @@ module Rbind
|
|
83
91
|
raise RuntimeError,"#{full_name} has no const called #{name}" if raise_ && !c
|
84
92
|
end
|
85
93
|
|
94
|
+
def each_const(childs=true,all=false,&block)
|
95
|
+
if block_given?
|
96
|
+
consts.each do |c|
|
97
|
+
next if !all && (c.ignore? || c.extern?)
|
98
|
+
yield c
|
99
|
+
end
|
100
|
+
return unless childs
|
101
|
+
each_container(all) do |t|
|
102
|
+
t.each_const(childs,all,&block)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
Enumerator.new(self,:each_const,childs,all)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def extern?
|
110
|
+
return super() if self.is_a?(RStruct)
|
111
|
+
|
112
|
+
# check if self is container holding only
|
113
|
+
# extern objects
|
114
|
+
each_type(false) do |t|
|
115
|
+
return false if !t.extern?
|
116
|
+
end
|
117
|
+
each_const(false) do |c|
|
118
|
+
return false if !c.extern?
|
119
|
+
end
|
120
|
+
each_operation do |t|
|
121
|
+
return false
|
122
|
+
end
|
123
|
+
true
|
124
|
+
end
|
125
|
+
|
126
|
+
def each_operation(all=false,&block)
|
127
|
+
if block_given?
|
128
|
+
operations.each do |ops|
|
129
|
+
ops.each do |o|
|
130
|
+
next if !all && o.ignore?
|
131
|
+
yield o
|
132
|
+
end
|
133
|
+
end
|
134
|
+
else
|
135
|
+
Enumerator.new(self,:each_operaion,all)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
86
139
|
def operations
|
87
140
|
@operations.values
|
88
141
|
end
|
data/lib/rbind/default_parser.rb
CHANGED
@@ -12,13 +12,14 @@ module Rbind
|
|
12
12
|
|
13
13
|
def normalize_flags(line_number,flags)
|
14
14
|
flags.map do |flag|
|
15
|
+
next if flag.empty?
|
15
16
|
if flag =~ /(\w*)(.*)/
|
16
17
|
DefaultParser.log.debug "input line #{line_number}: ignoring flag #{$2}" unless $2.empty?
|
17
18
|
$1.to_sym
|
18
19
|
else
|
19
20
|
raise "cannot parse flag #{flag.inspect}"
|
20
21
|
end
|
21
|
-
end
|
22
|
+
end.compact
|
22
23
|
end
|
23
24
|
|
24
25
|
def normalize_default_value(value)
|
@@ -108,34 +109,45 @@ module Rbind
|
|
108
109
|
|
109
110
|
def parse_class(line_number,string)
|
110
111
|
lines = string.split("\n")
|
111
|
-
a = lines.shift.rstrip
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
a = lines.shift.rstrip
|
113
|
+
unless a =~ /class ([a-zA-Z\.\d_:]*) ?:?([a-zA-Z\.\:, \d_]*)(.*)/
|
114
|
+
raise "cannot parse class #{a}"
|
115
|
+
end
|
116
|
+
name = $1
|
117
|
+
parent_classes = $2
|
118
|
+
flags = $3
|
119
|
+
parent_classes = if parent_classes
|
120
|
+
parent_classes.gsub(" ","").split(",").map do |name|
|
116
121
|
t = type(RBase.normalize(name),false)
|
117
122
|
# auto add parent class
|
118
123
|
t ||= add_type(RClass.new(RBase.normalize(name)))
|
119
124
|
end
|
120
125
|
end
|
126
|
+
flags = if flags
|
127
|
+
normalize_flags(line_number,flags.gsub(" ","").split("/").compact)
|
128
|
+
end
|
121
129
|
t = RClass.new(name,*parent_classes)
|
122
130
|
t = if t2 = type(t.full_name,false)
|
123
131
|
if !t2.is_a?(RClass) || (!t2.parent_classes.empty? && t2.parent_classes != t.parent_classes)
|
124
132
|
raise "Cannot add class #{t.full_name}. A different type #{t2} is already registered"
|
125
133
|
else
|
126
|
-
|
134
|
+
t.parent_classes.each do |p|
|
135
|
+
t2.add_parent p
|
136
|
+
end
|
127
137
|
t2
|
128
138
|
end
|
129
139
|
else
|
130
140
|
add_type(t)
|
131
141
|
t
|
132
142
|
end
|
143
|
+
t.flags = flags if flags
|
133
144
|
line_counter = 1
|
134
145
|
lines.each do |line|
|
135
146
|
a = attribute(line_counter+line_number,line,t)
|
136
147
|
t.add_attribute(a)
|
137
148
|
line_counter += 1
|
138
149
|
end
|
150
|
+
t.extern_package_name = @extern_package_name
|
139
151
|
[t,line_counter]
|
140
152
|
rescue RuntimeError => e
|
141
153
|
raise "input line #{line_number}: #{e}"
|
@@ -155,6 +167,7 @@ module Rbind
|
|
155
167
|
klass.add_attribute(a)
|
156
168
|
line_counter += 1
|
157
169
|
end
|
170
|
+
klass.extern_package_name = @extern_package_name
|
158
171
|
[klass,line_counter]
|
159
172
|
rescue RuntimeError => e
|
160
173
|
raise "input line #{line_number}: #{e}"
|
@@ -162,11 +175,19 @@ module Rbind
|
|
162
175
|
|
163
176
|
def parse_const(line_number,string)
|
164
177
|
raise "multi line const are not supported: #{string}" if string.split("\n").size > 1
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
178
|
+
unless string =~ /const ([a-zA-Z\.\d_:]*) ?([^\/]*)(.*)/
|
179
|
+
raise "cannot parse const #{string}"
|
180
|
+
end
|
181
|
+
name = $1
|
182
|
+
value = $2.chomp("\n").chomp(" ")
|
183
|
+
flags = $3
|
184
|
+
flags = if flags
|
185
|
+
normalize_flags(line_number,flags.gsub(" ","").split("/").compact)
|
186
|
+
end
|
187
|
+
|
169
188
|
c = RConst.new(name,value)
|
189
|
+
c.flags = flags if flags
|
190
|
+
c.extern_package_name = @extern_package_name
|
170
191
|
add_const(c)
|
171
192
|
[c,1]
|
172
193
|
end
|
@@ -211,7 +232,9 @@ module Rbind
|
|
211
232
|
[op,line_counter]
|
212
233
|
end
|
213
234
|
|
214
|
-
def parse(string)
|
235
|
+
def parse(string,extern_package_name=nil)
|
236
|
+
@extern_package_name = extern_package_name
|
237
|
+
|
215
238
|
a = split(string)
|
216
239
|
a.pop #remove number at the end of the file
|
217
240
|
line_number = 1
|
data/lib/rbind/generator_c.rb
CHANGED
@@ -82,13 +82,15 @@ module Rbind
|
|
82
82
|
class ConstsHelper < HelperBase
|
83
83
|
def wrap_consts
|
84
84
|
str = ""
|
85
|
-
@root.
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
85
|
+
@root.each_container do |type|
|
86
|
+
str2 = ""
|
87
|
+
type.each_const(false) do |c|
|
88
|
+
str2 += "#{c.csignature};\n"
|
89
|
+
end
|
90
|
+
if !str2.empty?
|
91
|
+
str += "\n\n//constants for #{type.full_name}\n"
|
92
|
+
str += str2
|
93
|
+
end
|
92
94
|
str
|
93
95
|
end
|
94
96
|
str
|
@@ -131,10 +133,6 @@ module Rbind
|
|
131
133
|
@type_conversion.result(t.binding)
|
132
134
|
end
|
133
135
|
|
134
|
-
def check_type?
|
135
|
-
type_check?
|
136
|
-
end
|
137
|
-
|
138
136
|
def wrap_conversions
|
139
137
|
str = ""
|
140
138
|
@root.each_type do |type|
|
@@ -152,13 +150,11 @@ module Rbind
|
|
152
150
|
|
153
151
|
def wrap_operations
|
154
152
|
str = ""
|
155
|
-
@root.
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
end.join("\n")
|
161
|
-
end.join("\n")
|
153
|
+
@root.each_container do |type|
|
154
|
+
str2 = ""
|
155
|
+
type.each_operation do |op|
|
156
|
+
str2 += "#{op.csignature};\n"
|
157
|
+
end
|
162
158
|
if !str2.empty?
|
163
159
|
str += "\n\n///methods for #{type.full_name}\n"
|
164
160
|
str += str2
|
@@ -252,21 +248,19 @@ module Rbind
|
|
252
248
|
|
253
249
|
def wrap_operations
|
254
250
|
str = ""
|
255
|
-
@root.
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
operation_wrapper(op)
|
260
|
-
end.join("\n")
|
261
|
-
end.join("\n")
|
251
|
+
@root.each_container do |type|
|
252
|
+
type.each_operation do |op|
|
253
|
+
str += operation_wrapper(op)
|
254
|
+
end
|
262
255
|
end
|
263
256
|
str
|
264
257
|
end
|
265
258
|
end
|
266
259
|
|
267
260
|
class CMakeListsHelper < HelperBase
|
268
|
-
def initialize(name,pkg_config=Array.new)
|
269
|
-
super
|
261
|
+
def initialize(name,pkg_config=Array.new,libs=Array.new)
|
262
|
+
super(name,pkg_config)
|
263
|
+
@libs = libs
|
270
264
|
@find_package = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","c","find_package.txt")).read)
|
271
265
|
end
|
272
266
|
|
@@ -277,9 +271,10 @@ module Rbind
|
|
277
271
|
end
|
278
272
|
|
279
273
|
def libs
|
280
|
-
@root.map do |pkg|
|
274
|
+
str = @root.map do |pkg|
|
281
275
|
"${#{pkg.upcase}_LIBS} ${#{pkg.upcase}_LDFLAGS}"
|
282
276
|
end.join(" ")
|
277
|
+
str += " " + @libs.join(" ")
|
283
278
|
end
|
284
279
|
|
285
280
|
def library_name
|
@@ -289,6 +284,7 @@ module Rbind
|
|
289
284
|
|
290
285
|
attr_accessor :includes
|
291
286
|
attr_accessor :library_name
|
287
|
+
attr_accessor :libs
|
292
288
|
attr_accessor :pkg_config
|
293
289
|
attr_accessor :generate_cmake
|
294
290
|
attr_accessor :output_path
|
@@ -305,10 +301,12 @@ module Rbind
|
|
305
301
|
@erb_conversions_hdr = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","c","conversions.hpp")).read)
|
306
302
|
@erb_cmakelists = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","c","CMakeLists.txt")).read)
|
307
303
|
@erb_find_package = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","c","find_package.txt")).read)
|
304
|
+
@erb_pkg_config = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","c","rbind.pc.in")).read)
|
308
305
|
@includes = Array.new
|
309
|
-
@
|
306
|
+
@pkg_config= Array.new
|
310
307
|
@library_name = library_name
|
311
308
|
@generate_cmake = true
|
309
|
+
@libs = []
|
312
310
|
end
|
313
311
|
|
314
312
|
def generate(path = @output_path)
|
@@ -321,33 +319,47 @@ module Rbind
|
|
321
319
|
file_operations_hdr = File.new(File.join(path,"operations.h"),"w")
|
322
320
|
file_conversions = File.new(File.join(path,"conversions.cc"),"w")
|
323
321
|
file_conversions_hdr = File.new(File.join(path,"conversions.hpp"),"w")
|
324
|
-
|
322
|
+
rbind_pkgs = Rbind.rbind_pkgs(@pkg_config)
|
325
323
|
|
326
|
-
types_hdr = TypesHelperHDR.new("
|
324
|
+
types_hdr = TypesHelperHDR.new("_#{library_name.upcase}_TYPES_H_",@root)
|
325
|
+
types_hdr.includes = rbind_pkgs.map do |p|
|
326
|
+
"<#{p}/types.h>"
|
327
|
+
end
|
327
328
|
file_types_hdr.write @erb_types_hdr.result(types_hdr.binding)
|
328
329
|
|
329
330
|
types = TypesHelper.new("types",@root)
|
330
331
|
file_types.write @erb_types.result(types.binding)
|
331
332
|
|
332
|
-
consts = ConstsHelper.new("
|
333
|
+
consts = ConstsHelper.new("_#{library_name.upcase}_CONSTS_H_",@root)
|
334
|
+
consts.includes = rbind_pkgs.map do |p|
|
335
|
+
"<#{p}/constants.h>"
|
336
|
+
end
|
333
337
|
file_consts.write @erb_consts.result(consts.binding)
|
334
338
|
|
335
|
-
conversions_hdr = ConversionsHelperHDR.new("
|
339
|
+
conversions_hdr = ConversionsHelperHDR.new("#{library_name.upcase}_CONVERSIONS_H_",@root)
|
340
|
+
conversions_hdr.includes = rbind_pkgs.map do |p|
|
341
|
+
"<#{p}/conversions.hpp>"
|
342
|
+
end
|
336
343
|
conversions_hdr.includes += includes
|
337
344
|
file_conversions_hdr.write @erb_conversions_hdr.result(conversions_hdr.binding)
|
338
345
|
|
339
346
|
conversions = ConversionsHelper.new("conversions",@root)
|
340
347
|
file_conversions.write @erb_conversions.result(conversions.binding)
|
341
348
|
|
342
|
-
operations_hdr = OperationsHDRHelper.new("
|
349
|
+
operations_hdr = OperationsHDRHelper.new("_#{library_name.upcase}_OPERATIONS_H_",@root)
|
343
350
|
file_operations_hdr.write @erb_operations_hdr.result(operations_hdr.binding)
|
344
351
|
|
345
352
|
operations = OperationsHelper.new("operations",@root)
|
346
353
|
file_operations.write @erb_operations.result(operations.binding)
|
347
354
|
|
348
|
-
if generate_cmake
|
349
|
-
|
355
|
+
if generate_cmake && !File.exist?(File.join(path,"CMakeLists.txt"))
|
356
|
+
file_cmakelists = File.new(File.join(path,"CMakeLists.txt"),"w")
|
357
|
+
cmakelists = CMakeListsHelper.new(@library_name,@pkg_config,@libs)
|
350
358
|
file_cmakelists.write @erb_cmakelists.result(cmakelists.binding)
|
359
|
+
if !File.exist?(File.join(path,"rbind.pc.in"))
|
360
|
+
file_pkg_config = File.new(File.join(path,"rbind.pc.in"),"w")
|
361
|
+
file_pkg_config.write @erb_pkg_config.result(Kernel.binding)
|
362
|
+
end
|
351
363
|
end
|
352
364
|
end
|
353
365
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Rbind
|
4
|
+
class GeneratorExtern
|
5
|
+
Config = Struct.new(:ruby_module_name)
|
6
|
+
|
7
|
+
attr_accessor :output_path
|
8
|
+
attr_accessor :ruby_module_name
|
9
|
+
def self.normalize_type_name(name)
|
10
|
+
name.gsub('::','.')
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(root)
|
14
|
+
@root = root
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate(path = @output_path,ruby_module_name = @ruby_module_name)
|
18
|
+
@output_path = path
|
19
|
+
@ruby_module_name = ruby_module_name
|
20
|
+
FileUtils.mkdir_p(path) if path && !File.directory?(path)
|
21
|
+
file_extern = File.new(File.join(path,"extern.rbind"),"w")
|
22
|
+
file_config = File.new(File.join(path,"config.rbind"),"w")
|
23
|
+
|
24
|
+
@root.each_type do |t|
|
25
|
+
if t.is_a? RClass
|
26
|
+
file_extern.write "class #{GeneratorExtern.normalize_type_name(t.full_name)} /Extern\n"
|
27
|
+
elsif t.is_a? RStruct
|
28
|
+
file_extern.write "struct #{GeneratorExtern.normalize_type_name(t.full_name)} /Extern\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@root.each_const do |c|
|
33
|
+
file_extern.write "const #{GeneratorExtern.normalize_type_name(c.full_name)} /Extern\n"
|
34
|
+
end
|
35
|
+
file_extern.write("\n")
|
36
|
+
file_config.write Config.new(ruby_module_name).to_yaml
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/rbind/generator_ruby.rb
CHANGED
@@ -57,11 +57,20 @@ module Rbind
|
|
57
57
|
|
58
58
|
|
59
59
|
def self.normalize_type_name(name)
|
60
|
-
name.split("::").map do |n|
|
60
|
+
names = name.split("::").map do |n|
|
61
61
|
n.gsub(/^(\w)(.*)/) do
|
62
62
|
$1.upcase+$2
|
63
63
|
end
|
64
|
-
end
|
64
|
+
end
|
65
|
+
n = names.last.split("_").first
|
66
|
+
if n == n.upcase
|
67
|
+
return names.join("::")
|
68
|
+
end
|
69
|
+
names.join("::").split("_").map do |n|
|
70
|
+
n.gsub(/^(\w)(.*)/) do
|
71
|
+
$1.upcase+$2
|
72
|
+
end
|
73
|
+
end.join("")
|
65
74
|
end
|
66
75
|
|
67
76
|
def self.normalize_basic_type_name(name)
|
@@ -76,21 +85,18 @@ module Rbind
|
|
76
85
|
end
|
77
86
|
|
78
87
|
def self.normalize_method_name(name)
|
79
|
-
name = name.to_s.
|
88
|
+
name = name.to_s.gsub(/\A#{RBase.cprefix}?/, "").gsub(/(?<!\A)\p{Lu}/u, '_\0').downcase
|
80
89
|
str = ""
|
81
90
|
name.split("_").each_with_index do |n,i|
|
82
|
-
if n.empty?
|
83
|
-
str += "_"
|
84
|
-
next
|
85
|
-
end
|
91
|
+
next if n.empty?
|
86
92
|
if n.size == 1 && i > 1
|
87
93
|
str += n
|
88
94
|
else
|
89
95
|
str += "_#{n}"
|
90
96
|
end
|
91
97
|
end
|
92
|
-
|
93
|
-
|
98
|
+
str = str[1..-1] #remove leading "_"
|
99
|
+
str = if str =~/^operator(.*)/
|
94
100
|
n = $1
|
95
101
|
if n =~ /\(\)/
|
96
102
|
raise "forbbiden method name #{name}"
|
@@ -112,7 +118,7 @@ module Rbind
|
|
112
118
|
n
|
113
119
|
end
|
114
120
|
else
|
115
|
-
|
121
|
+
str
|
116
122
|
end
|
117
123
|
end
|
118
124
|
|
@@ -133,15 +139,20 @@ module Rbind
|
|
133
139
|
end
|
134
140
|
|
135
141
|
class RBindHelper < HelperBase
|
136
|
-
|
137
|
-
attr_accessor :library_name
|
142
|
+
attr_reader :compact_namespace
|
138
143
|
|
139
|
-
def initialize(name, root)
|
140
|
-
|
144
|
+
def initialize(name, root,compact_namespace=false)
|
145
|
+
@compact_namespace = compact_namespace
|
146
|
+
super(name,root)
|
141
147
|
end
|
142
148
|
|
143
149
|
def normalize_t(name)
|
144
|
-
GeneratorRuby.normalize_type_name name
|
150
|
+
t = GeneratorRuby.normalize_type_name name
|
151
|
+
if compact_namespace
|
152
|
+
t.gsub(/^#{self.name}::/,"")
|
153
|
+
else
|
154
|
+
t
|
155
|
+
end
|
145
156
|
end
|
146
157
|
|
147
158
|
def normalize_bt(name)
|
@@ -152,9 +163,23 @@ module Rbind
|
|
152
163
|
GeneratorRuby.normalize_method_name name
|
153
164
|
end
|
154
165
|
|
166
|
+
def library_name
|
167
|
+
@root.library_name
|
168
|
+
end
|
169
|
+
|
170
|
+
def required_module_names
|
171
|
+
@root.required_module_names.map do |name|
|
172
|
+
"require '#{name.downcase}'\n"
|
173
|
+
end.join
|
174
|
+
end
|
175
|
+
|
176
|
+
def file_prefix
|
177
|
+
@root.file_prefix
|
178
|
+
end
|
179
|
+
|
155
180
|
def add_accessors
|
156
181
|
str = ""
|
157
|
-
@root.each_type do |t|
|
182
|
+
@root.root.each_type do |t|
|
158
183
|
next if t.basic_type? && !t.is_a?(RNamespace)
|
159
184
|
str += "\n#methods for #{t.full_name}\n"
|
160
185
|
if t.cdelete_method
|
@@ -163,28 +188,34 @@ module Rbind
|
|
163
188
|
str += "attach_function :#{normalize_m t.cdelete_method}_struct,"\
|
164
189
|
":#{t.cdelete_method},[#{normalize_t t.full_name}Struct],:void\n"
|
165
190
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
191
|
+
t.each_operation do |op|
|
192
|
+
return_type = if op.constructor?
|
193
|
+
"#{normalize_t op.owner.full_name}"
|
194
|
+
else
|
195
|
+
if op.return_type.basic_type?
|
196
|
+
":#{normalize_bt op.return_type.csignature}"
|
170
197
|
else
|
171
|
-
if op.return_type.
|
172
|
-
"
|
198
|
+
if op.return_type.extern_package_name
|
199
|
+
normalize_t("::#{op.return_type.extern_package_name}::#{op.return_type.full_name}")
|
173
200
|
else
|
174
|
-
|
201
|
+
normalize_t op.return_type.full_name
|
175
202
|
end
|
176
203
|
end
|
177
|
-
|
178
|
-
|
179
|
-
|
204
|
+
end
|
205
|
+
args = op.cparameters.map do |p|
|
206
|
+
if p.type.basic_type?
|
207
|
+
":#{normalize_bt p.type.csignature}"
|
208
|
+
else
|
209
|
+
if p.type.extern_package_name
|
210
|
+
normalize_t("::#{p.type.extern_package_name}::#{p.type.full_name}")
|
180
211
|
else
|
181
|
-
|
212
|
+
normalize_t p.type.full_name
|
182
213
|
end
|
183
214
|
end
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
end
|
215
|
+
end
|
216
|
+
fct_name = normalize_m op.cname
|
217
|
+
str += "attach_function :#{fct_name},:#{op.cname},[#{args.join(",")}],#{return_type}\n"
|
218
|
+
end
|
188
219
|
str+"\n"
|
189
220
|
end
|
190
221
|
str+"\n"
|
@@ -241,13 +272,14 @@ module Rbind
|
|
241
272
|
end
|
242
273
|
end
|
243
274
|
|
244
|
-
def initialize(name, root)
|
275
|
+
def initialize(name, root,compact_namespace = false)
|
245
276
|
@type_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rtype.rb")).read,nil,"-")
|
246
277
|
@type_constructor_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rtype_constructor.rb")).read,nil,"-")
|
247
278
|
@namespace_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rnamespace.rb")).read,nil,"-")
|
248
279
|
@static_method_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rstatic_method.rb")).read)
|
249
280
|
@method_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rmethod.rb")).read,nil,'-')
|
250
|
-
|
281
|
+
@compact_namespace = compact_namespace
|
282
|
+
super(name,root)
|
251
283
|
end
|
252
284
|
|
253
285
|
def name
|
@@ -275,39 +307,55 @@ module Rbind
|
|
275
307
|
ops = Array(@root.operation(@root.name,false))
|
276
308
|
return until ops
|
277
309
|
ops.map do |c|
|
310
|
+
next if c.ignore?
|
278
311
|
ch = OperationHelper.new(c)
|
279
312
|
@type_constructor_wrapper.result(ch.binding)
|
280
313
|
end.join("\n")
|
281
314
|
end
|
282
315
|
|
283
|
-
def add_consts
|
284
|
-
@root.consts.map do |c|
|
316
|
+
def add_consts(root=@root)
|
317
|
+
str = @root.consts.map do |c|
|
318
|
+
next if c.extern? || c.ignore?
|
285
319
|
" #{c.name} = #{GeneratorRuby::normalize_type_name(c.value)}\n"
|
286
320
|
end.join
|
321
|
+
return str unless @compact_namespace
|
322
|
+
|
323
|
+
root.each_type(false) do |t|
|
324
|
+
next if t.basic_type? && !t.is_a?(RNamespace)
|
325
|
+
str += add_consts(t) if name == GeneratorRuby.normalize_type_name(t.full_name)
|
326
|
+
end
|
327
|
+
str
|
287
328
|
end
|
288
329
|
|
289
|
-
def add_methods
|
330
|
+
def add_methods(root=@root)
|
290
331
|
str = ""
|
291
|
-
@root.
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
332
|
+
@root.each_operation do |op|
|
333
|
+
next if op.constructor?
|
334
|
+
oph = OperationHelper.new(op)
|
335
|
+
str += if op.instance_method?
|
336
|
+
@method_wrapper.result(oph.binding)
|
337
|
+
else
|
338
|
+
@static_method_wrapper.result(oph.binding)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
return str unless @compact_namespace
|
342
|
+
|
343
|
+
root.each_type(false) do |t|
|
344
|
+
next if t.basic_type? && !t.is_a?(RNamespace)
|
345
|
+
str += add_methods(t) if name == GeneratorRuby.normalize_type_name(t.full_name)
|
301
346
|
end
|
302
347
|
str
|
303
348
|
end
|
304
349
|
|
305
|
-
def add_types
|
350
|
+
def add_types(root = @root)
|
306
351
|
str = ""
|
307
|
-
|
352
|
+
root.each_type(false) do |t|
|
308
353
|
next if t.basic_type? && !t.is_a?(RNamespace)
|
309
|
-
|
310
|
-
|
354
|
+
str += if @compact_namespace && name == GeneratorRuby.normalize_type_name(t.full_name)
|
355
|
+
add_types(t)
|
356
|
+
else
|
357
|
+
RTypeHelper.new(t.name,t).result
|
358
|
+
end
|
311
359
|
end
|
312
360
|
str
|
313
361
|
end
|
@@ -317,6 +365,7 @@ module Rbind
|
|
317
365
|
end
|
318
366
|
|
319
367
|
def result
|
368
|
+
return "" if @root.extern?
|
320
369
|
str = if @root.is_a? RStruct
|
321
370
|
@type_wrapper.result(self.binding)
|
322
371
|
else
|
@@ -332,27 +381,34 @@ module Rbind
|
|
332
381
|
end
|
333
382
|
|
334
383
|
attr_accessor :module_name
|
384
|
+
attr_accessor :required_module_names
|
335
385
|
attr_accessor :library_name
|
336
386
|
attr_accessor :output_path
|
387
|
+
attr_accessor :file_prefix
|
388
|
+
attr_accessor :compact_namespace
|
389
|
+
attr_reader :root
|
337
390
|
|
391
|
+
def file_prefix
|
392
|
+
@file_prefix || GeneratorRuby.normalize_method_name(module_name)
|
393
|
+
end
|
338
394
|
|
339
395
|
def initialize(root,module_name ="Rbind",library_name="rbind_lib")
|
340
396
|
@root = root
|
341
397
|
@rbind_wrapper = ERB.new(File.open(File.join(File.dirname(__FILE__),"templates","ruby","rbind.rb")).read)
|
342
398
|
@module_name = module_name
|
343
399
|
@library_name = library_name
|
400
|
+
@compact_namespace = false
|
344
401
|
end
|
345
402
|
|
346
403
|
def generate(path=@output_path)
|
347
404
|
@output_path = path
|
348
405
|
FileUtils.mkdir_p(path) if path && !File.directory?(path)
|
349
|
-
file_rbind = File.new(File.join(path,"
|
350
|
-
file_types = File.new(File.join(path,"
|
406
|
+
file_rbind = File.new(File.join(path,"#{file_prefix}.rb"),"w")
|
407
|
+
file_types = File.new(File.join(path,"#{file_prefix}_types.rb"),"w")
|
351
408
|
|
352
|
-
types = RTypeHelper.new(@module_name,@root)
|
409
|
+
types = RTypeHelper.new(@module_name,@root,compact_namespace)
|
353
410
|
file_types.write types.result
|
354
|
-
rbind = RBindHelper.new(@module_name
|
355
|
-
rbind.library_name = @library_name
|
411
|
+
rbind = RBindHelper.new(@module_name,self,compact_namespace)
|
356
412
|
file_rbind.write @rbind_wrapper.result(rbind.binding)
|
357
413
|
end
|
358
414
|
end
|
data/lib/rbind/rbind.rb
CHANGED
@@ -9,6 +9,33 @@ module Rbind
|
|
9
9
|
attr_accessor :name
|
10
10
|
attr_accessor :pkg_config
|
11
11
|
|
12
|
+
def self.pkg_paths(pkg_name)
|
13
|
+
out = IO.popen("pkg-config --cflags-only-I #{pkg_name}")
|
14
|
+
paths = out.read.split("-I").delete_if(&:empty?).map do |i|
|
15
|
+
i.gsub("\n","").gsub(" ","")
|
16
|
+
end
|
17
|
+
raise "Cannot find pkg paths for #{pkg_name}" if paths.empty?
|
18
|
+
paths
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.rbind_pkgs(pkg_names)
|
22
|
+
pkg_names.find_all do |p|
|
23
|
+
!!(p =~ /^rbind_.*/)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.rbind_pkg_paths(pkg_names)
|
28
|
+
rbind_packages = rbind_pkgs(pkg_names)
|
29
|
+
rbind_paths = rbind_packages.map do |pkg|
|
30
|
+
paths = pkg_paths(pkg)
|
31
|
+
path = paths.find do |p|
|
32
|
+
File.exist?(File.join(p,pkg,"extern.rbind"))
|
33
|
+
end
|
34
|
+
raise "cannot find extern.rbind for rbind package #{pkg}" unless path
|
35
|
+
File.join(path,pkg)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
12
39
|
def initialize(name)
|
13
40
|
@name = name
|
14
41
|
@includes = []
|
@@ -17,6 +44,7 @@ module Rbind
|
|
17
44
|
lib_name = "rbind_#{name.downcase}"
|
18
45
|
@generator_c = GeneratorC.new(@parser,lib_name)
|
19
46
|
@generator_ruby = GeneratorRuby.new(@parser,name,lib_name)
|
47
|
+
@generator_extern = GeneratorExtern.new(@parser)
|
20
48
|
end
|
21
49
|
|
22
50
|
def parse(*files)
|
@@ -46,8 +74,18 @@ module Rbind
|
|
46
74
|
end
|
47
75
|
end
|
48
76
|
|
49
|
-
|
50
|
-
|
77
|
+
# parses other rbind packages
|
78
|
+
def parse_extern
|
79
|
+
paths = Rbind.rbind_pkg_paths(@pkg_config)
|
80
|
+
paths.each do |pkg|
|
81
|
+
config = YAML.load(File.open(File.join(pkg,"config.rbind")).read)
|
82
|
+
path = File.join(pkg,"extern.rbind")
|
83
|
+
::Rbind.log.info "parsing extern rbind pkg file #{path}"
|
84
|
+
parser.parse(File.open(path).read,config.ruby_module_name)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_headers_dry(*headers)
|
51
89
|
check_python
|
52
90
|
headers = if headers.empty?
|
53
91
|
includes
|
@@ -59,7 +97,11 @@ module Rbind
|
|
59
97
|
end
|
60
98
|
path = File.join(File.dirname(__FILE__),'tools','hdr_parser.py')
|
61
99
|
out = IO.popen("python #{path} #{headers.join(" ")}")
|
62
|
-
|
100
|
+
out.read
|
101
|
+
end
|
102
|
+
|
103
|
+
def parse_headers(*headers)
|
104
|
+
parser.parse parse_headers_dry(*headers)
|
63
105
|
end
|
64
106
|
|
65
107
|
def build
|
@@ -82,11 +124,18 @@ module Rbind
|
|
82
124
|
|
83
125
|
def generate(c_path = "src",ruby_path = "ruby/lib/#{name.downcase}")
|
84
126
|
generate_c c_path
|
127
|
+
generate_extern c_path
|
85
128
|
generate_ruby ruby_path
|
86
129
|
end
|
87
130
|
|
88
131
|
def generate_ruby(path)
|
89
132
|
::Rbind.log.info "generate ruby ffi wrappers"
|
133
|
+
paths = Rbind.rbind_pkg_paths(@pkg_config)
|
134
|
+
modules = paths.map do |pkg|
|
135
|
+
config = YAML.load(File.open(File.join(pkg,"config.rbind")).read)
|
136
|
+
config.ruby_module_name
|
137
|
+
end
|
138
|
+
@generator_ruby.required_module_names = modules
|
90
139
|
@generator_ruby.generate(path)
|
91
140
|
end
|
92
141
|
|
@@ -97,6 +146,10 @@ module Rbind
|
|
97
146
|
@generator_c.generate(path)
|
98
147
|
end
|
99
148
|
|
149
|
+
def generate_extern(path)
|
150
|
+
@generator_extern.generate(path,@generator_ruby.module_name)
|
151
|
+
end
|
152
|
+
|
100
153
|
def use_namespace(name)
|
101
154
|
t = if name.is_a? String
|
102
155
|
parser.type(name)
|
@@ -114,6 +167,10 @@ module Rbind
|
|
114
167
|
@parser.on_type_not_found(&block)
|
115
168
|
end
|
116
169
|
|
170
|
+
def libs
|
171
|
+
@generator_c.libs
|
172
|
+
end
|
173
|
+
|
117
174
|
def method_missing(m,*args)
|
118
175
|
t = @parser.type(m.to_s,false)
|
119
176
|
return t if t
|
@@ -1,5 +1,4 @@
|
|
1
1
|
cmake_minimum_required(VERSION 2.6)
|
2
|
-
|
3
2
|
PROJECT(<%= library_name %> CXX)
|
4
3
|
|
5
4
|
include(FindPkgConfig)
|
@@ -9,3 +8,17 @@ SET(RBIND_SRC types.cc operations.cc conversions.cc)
|
|
9
8
|
ADD_LIBRARY(<%= library_name %> SHARED ${RBIND_SRC})
|
10
9
|
|
11
10
|
TARGET_LINK_LIBRARIES(<%= library_name %> <%= libs %>)
|
11
|
+
|
12
|
+
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/rbind.pc.in ${CMAKE_CURRENT_BINARY_DIR}/<%= library_name %>.pc @ONLY)
|
13
|
+
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/<%= library_name %>.pc DESTINATION lib/pkgconfig)
|
14
|
+
|
15
|
+
install(TARGETS <%= library_name %> LIBRARY DESTINATION lib)
|
16
|
+
install(FILES types.h operations.h conversions.hpp DESTINATION include/${PROJECT_NAME}/${DIR})
|
17
|
+
|
18
|
+
if (EXISTS ${PROJECT_SOURCE_DIR}/extern.rbind)
|
19
|
+
install(FILES ${PROJECT_SOURCE_DIR}/extern.rbind DESTINATION include/${PROJECT_NAME}/${DIR})
|
20
|
+
endif()
|
21
|
+
|
22
|
+
if (EXISTS ${PROJECT_SOURCE_DIR}/config.rbind)
|
23
|
+
install(FILES ${PROJECT_SOURCE_DIR}/config.rbind DESTINATION include/${PROJECT_NAME}/${DIR})
|
24
|
+
endif()
|
@@ -0,0 +1,11 @@
|
|
1
|
+
prefix=@CMAKE_INSTALL_PREFIX@
|
2
|
+
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
3
|
+
libdir=${prefix}/lib
|
4
|
+
includedir=${prefix}/include
|
5
|
+
|
6
|
+
Name: @PROJECT_NAME@
|
7
|
+
Description: @PROJECT_DESCRIPTION@
|
8
|
+
Version: @PROJECT_VERSION@
|
9
|
+
Requires: <%= pkg_config.join(" ") %>
|
10
|
+
Libs: -L${libdir} -l@PROJECT_NAME@
|
11
|
+
Cflags: -I${includedir}
|
@@ -21,19 +21,15 @@ const <%= full_name %>* fromC(const <%= cname %>* ptr)
|
|
21
21
|
throw std::runtime_error(str + static_cast<const std::type_info*>(ptr->type_id)->name()
|
22
22
|
+ " but was expecting " + typeid(<%= full_name %>).name());
|
23
23
|
}
|
24
|
-
|
25
24
|
// check version
|
26
25
|
if(ptr->version != <%= version %>)
|
27
26
|
throw std::runtime_error("wrong object version for <%= full_name %>");
|
28
27
|
<%- end %>
|
29
|
-
|
30
28
|
// check size
|
31
|
-
if(sizeof(<%= full_name %>) > ptr->size)
|
32
|
-
throw std::runtime_error("wrong object size for <%= full_name
|
33
|
-
|
29
|
+
if(ptr->size && sizeof(<%= full_name %>) > ptr->size)
|
30
|
+
throw std::runtime_error("wrong object size for <%= full_name %>.");
|
34
31
|
if(!ptr->obj_ptr)
|
35
32
|
throw std::runtime_error("object for <%= full_name %> was deleted!");
|
36
|
-
|
37
33
|
return static_cast<const <%= full_name %>*>(ptr->obj_ptr);
|
38
34
|
}
|
39
35
|
|
@@ -18,7 +18,7 @@ class <%= name %>
|
|
18
18
|
native_type FFI::Type::POINTER
|
19
19
|
|
20
20
|
def self.new(*args)
|
21
|
-
if args.first.is_a?(FFI::Pointer)
|
21
|
+
if args.first.is_a?(FFI::Pointer) || args.first.is_a?(<%= name %>Struct)
|
22
22
|
raise ArgumentError, "too many arguments for creating #{self.name} from Pointer" unless args.size == 1
|
23
23
|
return super(args.first)
|
24
24
|
end
|
data/rbind.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbind
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-20 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ''
|
15
15
|
email:
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- lib/rbind/core/rvector.rb
|
37
37
|
- lib/rbind/default_parser.rb
|
38
38
|
- lib/rbind/generator_c.rb
|
39
|
+
- lib/rbind/generator_extern.rb
|
39
40
|
- lib/rbind/generator_ruby.rb
|
40
41
|
- lib/rbind/logger.rb
|
41
42
|
- lib/rbind/rbind.rb
|
@@ -47,6 +48,7 @@ files:
|
|
47
48
|
- lib/rbind/templates/c/operation_wrapper.cc
|
48
49
|
- lib/rbind/templates/c/operations.cc
|
49
50
|
- lib/rbind/templates/c/operations.h
|
51
|
+
- lib/rbind/templates/c/rbind.pc.in
|
50
52
|
- lib/rbind/templates/c/type_conversion.cc
|
51
53
|
- lib/rbind/templates/c/type_conversion.hpp
|
52
54
|
- lib/rbind/templates/c/type_delete.h
|