ffi-compiler 0.1.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-