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 +4 -4
- data/ffi-compiler.gemspec +1 -1
- data/lib/ffi-compiler/compile_task.rb +35 -11
- data/lib/ffi-compiler/fake_ffi/ffi.rb +135 -23
- metadata +16 -16
- data/lib/ffi-compiler/ffi-compiler.iml +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d72c341f9ccb50429bfd8a3542d3c9481f7e4d2
|
4
|
+
data.tar.gz: 780d11e250a8e1637d287d8482c7eb319d170db8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4d9af481db298d53bba6d89b85f4f288043748ca736f84f751f1cb16ad829be4719fbf5faab58a14ebdbaa91a01d0cafbaa31104c1dbfaae6cd9093f371c1e5
|
7
|
+
data.tar.gz: f7d499575077854ec5913209f0ec8fb83e01028a90b93ba86c8b221bc9b31f8c135a3df6370b47cc0a5f7a611167c1ae4f0971c6cec7032e40d435ff2123395e
|
data/ffi-compiler.gemspec
CHANGED
@@ -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
|
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 =
|
107
|
-
obj_files =
|
108
|
-
|
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 =
|
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} #{
|
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
|
-
:
|
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
|
-
|
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
|
-
|
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 =
|
168
|
+
FFI.exporter.mod = mod
|
116
169
|
end
|
117
170
|
|
118
|
-
def attach_function(
|
119
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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.
|
163
|
-
|
256
|
+
|
257
|
+
def self.in
|
258
|
+
ptr(:in)
|
164
259
|
end
|
165
|
-
|
166
|
-
def self.
|
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.
|
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:
|
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
|
-
-
|
75
|
+
- LICENSE
|
76
76
|
- README.md
|
77
77
|
- Rakefile
|
78
|
-
-
|
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.
|
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
|
-
|