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.
@@ -3,3 +3,4 @@ require 'rbind/core'
3
3
  require 'rbind/default_parser'
4
4
  require 'rbind/generator_c'
5
5
  require 'rbind/generator_ruby'
6
+ require 'rbind/generator_extern'
@@ -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
@@ -1,7 +1,7 @@
1
1
 
2
2
  module Rbind
3
3
  class RClass < RStruct
4
- attr_accessor :parent_classes
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
- @type_check = true
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(&block) if childs && t.respond_to?(: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
@@ -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.split(" : ")
112
- name = a[0].split(" ")[1]
113
- parents = a[1]
114
- parent_classes = if parents
115
- parents.split(", ").map do |name|
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
- t2.parent_classes = t.instance_variable_get(:@parent_classes)
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
- a = string.split(" ")
166
- raise "not a constant: #{string}" unless a.shift == "const"
167
- name = a.shift
168
- value = a.join(" ")
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
@@ -82,13 +82,15 @@ module Rbind
82
82
  class ConstsHelper < HelperBase
83
83
  def wrap_consts
84
84
  str = ""
85
- @root.each_type do |type|
86
- next if !type.container?
87
- next if type.consts.empty?
88
- str += "\n\n//constants for #{type.full_name}\n"
89
- str += type.consts.map do |c|
90
- "#{c.csignature};\n"
91
- end.join
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.each_type do |type|
156
- next unless type.respond_to? :operations
157
- str2 = type.operations.map do |ops|
158
- ops.map do |op|
159
- "#{op.csignature};"
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.each_type do |type|
256
- next unless type.respond_to? :operations
257
- str += type.operations.map do |ops|
258
- ops.map do |op|
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
- @pkgconfig= Array.new
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
- file_cmakelists = File.new(File.join(path,"CMakeLists.txt"),"w")
322
+ rbind_pkgs = Rbind.rbind_pkgs(@pkg_config)
325
323
 
326
- types_hdr = TypesHelperHDR.new("_RBIND_TYPES_H_",@root)
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("_RBIND_CONSTS_H_",@root)
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("_RBIND_CONVERSIONS_H_",@root)
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("_RBIND_OPERATIONS_H_",@root)
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
- cmakelists = CMakeListsHelper.new(@library_name,@pkg_config)
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
@@ -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.join("::")
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.sub(/\A#{RBase.cprefix}?/, "").gsub(/(?<!\A)\p{Lu}/u, '_\0').downcase
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
- name = str[1,str.size-1]
93
- name = if name =~/^operator(.*)/
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
- name
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
- #TODO
137
- attr_accessor :library_name
142
+ attr_reader :compact_namespace
138
143
 
139
- def initialize(name, root)
140
- super
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
- str += t.operations.map do |ops|
167
- ops.map do |op|
168
- return_type = if op.constructor?
169
- "#{normalize_t op.owner.full_name}"
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.basic_type?
172
- ":#{normalize_bt op.return_type.csignature}"
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
- "#{normalize_t op.return_type.full_name}"
201
+ normalize_t op.return_type.full_name
175
202
  end
176
203
  end
177
- args = op.cparameters.map do |p|
178
- if p.type.basic_type?
179
- ":#{normalize_bt p.type.csignature}"
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
- "#{normalize_t p.type.full_name}"
212
+ normalize_t p.type.full_name
182
213
  end
183
214
  end
184
- fct_name = normalize_m op.cname
185
- "attach_function :#{fct_name},:#{op.cname},[#{args.join(",")}],#{return_type}\n"
186
- end.join
187
- end.join
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
- super
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.operations.each do |ops|
292
- ops.each do |op|
293
- next if op.constructor?
294
- oph = OperationHelper.new(op)
295
- str += if op.instance_method?
296
- @method_wrapper.result(oph.binding)
297
- else
298
- @static_method_wrapper.result(oph.binding)
299
- end
300
- end
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
- @root.each_type(false) do |t|
352
+ root.each_type(false) do |t|
308
353
  next if t.basic_type? && !t.is_a?(RNamespace)
309
- t = RTypeHelper.new(t.name,t)
310
- str += t.result
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,"opencv.rb"),"w")
350
- file_types = File.new(File.join(path,"opencv_types.rb"),"w")
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,@root)
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
@@ -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
- def parse_headers(*headers)
50
- ::Rbind.log.info "parse header files"
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
- parser.parse out.read
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
 
@@ -1,5 +1,6 @@
1
1
  require 'ffi'
2
- require File.join(File.dirname(__FILE__),'opencv_types')
2
+ require File.join(File.dirname(__FILE__),'<%= file_prefix %>_types.rb')
3
+ <%= required_module_names %>
3
4
 
4
5
  module <%= name %>
5
6
  # low level accessors the wrapped library
@@ -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
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rbind'
3
- s.version = '0.0.2'
4
- s.date = '2013-06-17'
3
+ s.version = '0.0.3'
4
+ s.date = '2013-06-20'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ['Alexander Duda']
7
7
  s.email = ['Alexander.Duda@dfki.de']
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.2
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-17 00:00:00.000000000 Z
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