ffi-compiler 0.1.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 87b97ccecbaf39ef45a53f9337e6ecade626e876
4
- data.tar.gz: a24d4e75bc369faf590da123fe91b281f85cda09
3
+ metadata.gz: 0d72c341f9ccb50429bfd8a3542d3c9481f7e4d2
4
+ data.tar.gz: 780d11e250a8e1637d287d8482c7eb319d170db8
5
5
  SHA512:
6
- metadata.gz: f8359cadf2f988f7099fd167a657af27ce8b1ebfb57bf459a84ef48ce6dda08c66b38ccd138e8e04fff954daeedd7bf8fe8cbe96958f41c114e8615ce7e11331
7
- data.tar.gz: de1f3dbd908f0144c19ba89d290e6a6d39e35c35686eba25784c045536b0b5ecc71ecd865411c5b4564b74f0c956bb4660d663b3672092a9e9fb786bc8929a54
6
+ metadata.gz: a4d9af481db298d53bba6d89b85f4f288043748ca736f84f751f1cb16ad829be4719fbf5faab58a14ebdbaa91a01d0cafbaa31104c1dbfaae6cd9093f371c1e5
7
+ data.tar.gz: f7d499575077854ec5913209f0ec8fb83e01028a90b93ba86c8b221bc9b31f8c135a3df6370b47cc0a5f7a611167c1ae4f0971c6cec7032e40d435ff2123395e
data/ffi-compiler.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'ffi-compiler'
3
- s.version = '0.1.3'
3
+ s.version = '1.0.0'
4
4
  s.author = 'Wayne Meissner'
5
5
  s.email = 'wmeissner@gmail.com'
6
6
  s.homepage = 'http://wiki.github.com/ffi/ffi'
@@ -13,10 +13,13 @@ module FFI
13
13
 
14
14
  class CompileTask < Rake::TaskLib
15
15
  attr_reader :cflags, :cxxflags, :ldflags, :libs, :platform
16
+ attr_accessor :name, :ext_dir, :source_dirs, :exclude
16
17
 
17
18
  def initialize(name)
18
19
  @name = File.basename(name)
19
20
  @ext_dir = File.dirname(name)
21
+ @source_dirs = [@ext_dir]
22
+ @exclude = []
20
23
  @defines = []
21
24
  @include_paths = []
22
25
  @library_paths = []
@@ -34,6 +37,14 @@ module FFI
34
37
  define_task!
35
38
  end
36
39
 
40
+ def add_include_path(path)
41
+ @include_paths << path
42
+ end
43
+
44
+ def add_define(name, value=1)
45
+ @defines << "-D#{name}=#{value}"
46
+ end
47
+
37
48
  def have_func?(func)
38
49
  main = <<-C_FILE
39
50
  extern void #{func}();
@@ -95,20 +106,28 @@ module FFI
95
106
  lib_name = File.join(out_dir, Platform.system.map_library_name(@name))
96
107
 
97
108
  iflags = @include_paths.uniq.map { |p| "-I#{p}" }
98
- defines = @functions.uniq.map { |f| "-DHAVE_#{f.upcase}=1" }
99
- defines << @headers.uniq.map { |h| "-DHAVE_#{h.upcase.sub(/\./, '_')}=1" }
109
+ @defines << @functions.uniq.map { |f| "-DHAVE_#{f.upcase}=1" }
110
+ @defines << @headers.uniq.map { |h| "-DHAVE_#{h.upcase.sub(/\./, '_')}=1" }
100
111
 
101
- cflags = (@cflags + pic_flags + iflags + defines).join(' ')
102
- cxxflags = (@cxxflags + @cflags + pic_flags + iflags + defines).join(' ')
112
+ cflags = (@cflags + pic_flags + iflags + @defines).join(' ')
113
+ cxxflags = (@cxxflags + @cflags + pic_flags + iflags + @defines).join(' ')
103
114
  ld_flags = (@library_paths.map { |path| "-L#{path}" } + @ldflags).join(' ')
104
115
  libs = (@libraries.map { |l| "-l#{l}" } + @libs).join(' ')
105
116
 
106
- src_files = FileList["#{@ext_dir}/**/*.{c,cpp}"]
107
- obj_files = src_files.ext('.o').map { |f| File.join(out_dir, f.sub(/^#{@ext_dir}\//, '')) }
108
- ld = src_files.detect { |f| f =~ /\.cpp$/ } ? cxx : cc
109
-
117
+ src_files = []
118
+ obj_files = []
119
+ @source_dirs.each do |dir|
120
+ files = FileList["#{dir}/**/*.{c,cpp}"]
121
+ unless @exclude.empty?
122
+ files.delete_if { |f| f =~ Regexp.union(*@exclude) }
123
+ end
124
+ src_files += files
125
+ obj_files += files.ext('.o').map { |f| File.join(out_dir, f.sub(/^#{dir}\//, '')) }
126
+ end
127
+
128
+ index = 0
110
129
  src_files.each do |src|
111
- obj_file = File.join(out_dir, src.sub(/\.(c|cpp)$/, '.o').sub(/^#{@ext_dir}\//, ''))
130
+ obj_file = obj_files[index]
112
131
  if src =~ /\.c$/
113
132
  file obj_file => [ src, File.dirname(obj_file) ] do |t|
114
133
  sh "#{cc} #{cflags} -o #{t.name} -c #{t.prerequisites[0]}"
@@ -121,8 +140,11 @@ module FFI
121
140
  end
122
141
 
123
142
  CLEAN.include(obj_file)
143
+ index += 1
124
144
  end
125
145
 
146
+ ld = src_files.detect { |f| f =~ /\.cpp$/ } ? cxx : cc
147
+
126
148
  # create all the directories for the output files
127
149
  obj_files.map { |f| File.dirname(f) }.sort.uniq.map { |d| directory d }
128
150
 
@@ -135,7 +157,7 @@ module FFI
135
157
  @exports.each do |e|
136
158
  desc "Export #{e[:rb_file]}"
137
159
  file e[:header] => [ e[:rb_file] ] do |t|
138
- ruby "-I#{File.join(File.dirname(__FILE__), 'fake_ffi')} #{File.join(File.dirname(__FILE__), 'exporter.rb')} #{t.prerequisites[0]} #{t.name}"
160
+ ruby "-I#{File.join(File.dirname(__FILE__), 'fake_ffi')} -I#{File.dirname(t.prerequisites[0])} #{File.join(File.dirname(__FILE__), 'exporter.rb')} #{t.prerequisites[0]} #{t.name}"
139
161
  end
140
162
 
141
163
  obj_files.each { |o| file o => [ e[:header] ] }
@@ -199,8 +221,10 @@ module FFI
199
221
  File.open(path, 'w') do |f|
200
222
  f << src
201
223
  end
224
+ cflags = opts.join(' ')
225
+ output = File.join(dir, 'ffi-test')
202
226
  begin
203
- return system "#{cc} #{opts.join(' ')} -o #{File.join(dir, 'ffi-test')} #{path} > /dev/null 2>&1"
227
+ return system "#{cc} #{cflags} -o #{output} -c #{path} > #{path}.log 2>&1"
204
228
  rescue
205
229
  return false
206
230
  end
@@ -3,11 +3,11 @@ module FFI
3
3
  def self.exporter=(exporter)
4
4
  @@exporter = exporter
5
5
  end
6
-
6
+
7
7
  def self.exporter
8
- @@exporter
8
+ @@exporter ||= Exporter.new(nil)
9
9
  end
10
-
10
+
11
11
  class Type
12
12
  attr_reader :name
13
13
  def initialize(name)
@@ -26,8 +26,28 @@ module FFI
26
26
  super("struct #{struct_class.to_s.gsub('::', '_')}")
27
27
  end
28
28
  end
29
-
29
+
30
+ class CallbackInfo
31
+ attr_reader :return_type
32
+ attr_reader :arg_types
33
+ attr_reader :options
34
+
35
+ def initialize(return_type, arg_types = [], *other)
36
+ @return_type = return_type
37
+ @arg_types = arg_types
38
+ @options = options
39
+ end
40
+
41
+ def name(name)
42
+ params = @arg_types.empty? ? 'void' : @arg_types.map(&:name).join(', ')
43
+ "#{@return_type.name} (*#{name})(#{params})"
44
+ end
45
+ end
46
+
30
47
  PrimitiveTypes = {
48
+ :void => 'void',
49
+ :bool => 'bool',
50
+ :string => 'const char *',
31
51
  :char => 'char',
32
52
  :uchar => 'unsigned char',
33
53
  :short => 'short',
@@ -36,15 +56,29 @@ module FFI
36
56
  :uint => 'unsigned int',
37
57
  :long => 'long',
38
58
  :ulong => 'unsigned long',
59
+ :long_long => 'long long',
60
+ :ulong_long => 'unsigned long long',
39
61
  :float => 'float',
40
62
  :double => 'double',
63
+ :long_double => 'long double',
41
64
  :pointer => 'void *',
42
- :string => 'const char *',
65
+ :int8 => 'int8_t',
66
+ :uint8 => 'uint8_t',
67
+ :int16 => 'int16_t',
68
+ :uint16 => 'uint16_t',
69
+ :int32 => 'int32_t',
70
+ :uint32 => 'uint32_t',
71
+ :int64 => 'int64_t',
72
+ :uint64 => 'uint64_t',
73
+ :buffer_in => 'const in void *',
74
+ :buffer_out => 'out void *',
75
+ :buffer_inout => 'inout void *',
76
+ :varargs => '...'
43
77
  }
44
-
78
+
45
79
  TypeMap = {}
46
80
  def self.find_type(type)
47
- return type if type.is_a?(Type)
81
+ return type if type.is_a?(Type) or type.is_a?(CallbackInfo)
48
82
 
49
83
  t = TypeMap[type]
50
84
  return t unless t.nil?
@@ -55,12 +89,19 @@ module FFI
55
89
  raise TypeError.new("cannot resolve type #{type}")
56
90
  end
57
91
 
92
+ class Function
93
+ def initialize(*args)
94
+ end
95
+ end
96
+
58
97
  class Exporter
59
- attr_reader :mod, :functions
98
+ attr_accessor :mod
99
+ attr_reader :functions, :callbacks, :structs
60
100
 
61
101
  def initialize(mod)
62
102
  @mod = mod
63
103
  @functions = []
104
+ @callbacks = {}
64
105
  @structs = []
65
106
  end
66
107
 
@@ -71,7 +112,11 @@ module FFI
71
112
  def struct(name, fields)
72
113
  @structs << { name: name, fields: fields.dup }
73
114
  end
74
-
115
+
116
+ def callback(name, cb)
117
+ @callbacks[name] = cb
118
+ end
119
+
75
120
  def dump(out_file)
76
121
  File.open(out_file, 'w') do |f|
77
122
  guard = File.basename(out_file).upcase.gsub('.', '_').gsub('/', '_')
@@ -88,11 +133,19 @@ module FFI
88
133
  #endif
89
134
 
90
135
  HEADER
91
-
136
+
137
+ @callbacks.each do |name, cb|
138
+ f.puts "typedef #{cb.name(name)};"
139
+ end
92
140
  @structs.each do |s|
93
141
  f.puts "struct #{s[:name].gsub('::', '_')} {"
94
142
  s[:fields].each do |field|
95
- f.puts "#{' ' * 4}#{field[:type].name} #{field[:name].to_s};"
143
+ if field[:type].is_a?(CallbackInfo)
144
+ type = field[:type].name(field[:name].to_s)
145
+ else
146
+ type = "#{field[:type].name} #{field[:name].to_s}"
147
+ end
148
+ f.puts "#{' ' * 4}#{type};"
96
149
  end
97
150
  f.puts '};'
98
151
  f.puts
@@ -112,17 +165,31 @@ module FFI
112
165
 
113
166
  module Library
114
167
  def self.extended(mod)
115
- FFI.exporter = Exporter.new(mod)
168
+ FFI.exporter.mod = mod
116
169
  end
117
170
 
118
- def attach_function(*args)
119
- FFI.exporter.attach(args[0], args[0], find_type(args[2]), args[1].map { |t| find_type(t) })
171
+ def attach_function(name, func, args, returns = nil, options = nil)
172
+ mname, a2, a3, a4, a5 = name, func, args, returns, options
173
+ cname, arg_types, ret_type, opts = (a4 && (a2.is_a?(String) || a2.is_a?(Symbol))) ? [ a2, a3, a4, a5 ] : [ mname.to_s, a2, a3, a4 ]
174
+ arg_types = arg_types.map { |e| find_type(e) }
175
+ FFI.exporter.attach(mname, cname, find_type(ret_type), arg_types)
120
176
  end
121
177
 
122
178
  def ffi_lib(*args)
123
179
 
124
180
  end
125
181
 
182
+ def callback(*args)
183
+ name, params, ret = if args.length == 3
184
+ args
185
+ else
186
+ [ nil, args[0], args[1] ]
187
+ end
188
+ native_params = params.map { |e| find_type(e) }
189
+ cb = FFI::CallbackInfo.new(find_type(ret), native_params)
190
+ FFI.exporter.callback(name, cb) if name
191
+ end
192
+
126
193
  TypeMap = {}
127
194
  def find_type(type)
128
195
  t = TypeMap[type]
@@ -138,15 +205,43 @@ module FFI
138
205
 
139
206
  class Struct
140
207
  def self.layout(*args)
208
+ return if args.size.zero?
141
209
  fields = []
142
- i = 0
143
- while i < args.length
144
- fields << { name: args[i], type: find_type(args[i+1]) }
145
- i += 2
210
+ if args.first.kind_of?(Hash)
211
+ args.first.each do |name, type|
212
+ fields << { :name => name, :type => find_type(type), :offset => nil }
213
+ end
214
+ else
215
+ i = 0
216
+ while i < args.size
217
+ name, type, offset = args[i], args[i+1], nil
218
+ i += 2
219
+ if args[i].kind_of?(Integer)
220
+ offset = args[i]
221
+ i += 1
222
+ end
223
+ fields << { :name => name, :type => find_type(type), :offset => offset }
224
+ end
146
225
  end
147
226
  FFI.exporter.struct(self.to_s, fields)
148
227
  end
149
228
 
229
+ def initialize
230
+ @data = {}
231
+ end
232
+
233
+ def [](name)
234
+ @data[name]
235
+ end
236
+
237
+ def []=(name, value)
238
+ @data[name] = value
239
+ end
240
+
241
+ def self.callback(params, ret)
242
+ FFI::CallbackInfo.new(find_type(ret), params.map { |e| find_type(e) })
243
+ end
244
+
150
245
  TypeMap = {}
151
246
  def self.find_type(type)
152
247
  t = TypeMap[type]
@@ -158,13 +253,30 @@ module FFI
158
253
 
159
254
  TypeMap[type] = FFI.find_type(type)
160
255
  end
161
-
162
- def self.by_value
163
- StructByValue.new(self)
256
+
257
+ def self.in
258
+ ptr(:in)
164
259
  end
165
-
166
- def self.by_ref
260
+
261
+ def self.out
262
+ ptr(:out)
263
+ end
264
+
265
+ def self.ptr(flags = :inout)
167
266
  StructByReference.new(self)
168
267
  end
268
+
269
+ def self.val
270
+ StructByValue.new(self)
271
+ end
272
+
273
+ def self.by_value
274
+ self.val
275
+ end
276
+
277
+ def self.by_ref(flags = :inout)
278
+ self.ptr(flags)
279
+ end
280
+
169
281
  end
170
282
  end
metadata CHANGED
@@ -1,69 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-compiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wayne Meissner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-04-19 00:00:00.000000000 Z
11
+ date: 2016-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: ffi
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.0.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.0.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rubygems-tasks
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  description: Ruby FFI library
@@ -72,16 +72,15 @@ executables: []
72
72
  extensions: []
73
73
  extra_rdoc_files: []
74
74
  files:
75
- - ffi-compiler.gemspec
75
+ - LICENSE
76
76
  - README.md
77
77
  - Rakefile
78
- - LICENSE
78
+ - ffi-compiler.gemspec
79
79
  - lib/ffi-compiler/compile_task.rb
80
80
  - lib/ffi-compiler/export_task.rb
81
81
  - lib/ffi-compiler/exporter.rb
82
82
  - lib/ffi-compiler/fake_ffi/ffi-compiler/loader.rb
83
83
  - lib/ffi-compiler/fake_ffi/ffi.rb
84
- - lib/ffi-compiler/ffi-compiler.iml
85
84
  - lib/ffi-compiler/loader.rb
86
85
  - lib/ffi-compiler/platform.rb
87
86
  - lib/ffi-compiler/task.rb
@@ -95,18 +94,19 @@ require_paths:
95
94
  - lib
96
95
  required_ruby_version: !ruby/object:Gem::Requirement
97
96
  requirements:
98
- - - '>='
97
+ - - ">="
99
98
  - !ruby/object:Gem::Version
100
99
  version: '1.9'
101
100
  required_rubygems_version: !ruby/object:Gem::Requirement
102
101
  requirements:
103
- - - '>='
102
+ - - ">="
104
103
  - !ruby/object:Gem::Version
105
104
  version: '0'
106
105
  requirements: []
107
106
  rubyforge_project:
108
- rubygems_version: 2.0.0
107
+ rubygems_version: 2.5.1
109
108
  signing_key:
110
109
  specification_version: 4
111
110
  summary: Ruby FFI Rakefile generator
112
111
  test_files: []
112
+ has_rdoc: false
@@ -1,14 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <module type="RUBY_MODULE" version="4">
3
- <component name="NewModuleRootManager" inherit-compiler-output="true">
4
- <exclude-output />
5
- <content url="file://$MODULE_DIR$">
6
- <sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
7
- </content>
8
- <orderEntry type="jdk" jdkName="RVM: ruby-1.9.3-p392" jdkType="RUBY_SDK" />
9
- <orderEntry type="sourceFolder" forTests="false" />
10
- <orderEntry type="library" scope="PROVIDED" name="ffi (v1.4.0, RVM: ruby-1.9.3-p392) [gem]" level="application" />
11
- <orderEntry type="library" scope="PROVIDED" name="rake (v10.0.3, RVM: ruby-1.9.3-p392) [gem]" level="application" />
12
- </component>
13
- </module>
14
-