rdp-ffi-inliner 0.2.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/History.txt +47 -0
- data/README.rdoc +87 -0
- data/Rakefile +44 -0
- data/examples/ex_1.rb +23 -0
- data/lib/ffi-inliner.rb +6 -0
- data/lib/ffi-inliner/inliner.rb +308 -0
- data/lib/ffi-inliner/version.rb +3 -0
- data/out +48 -0
- data/spec/ffi-inliner/cache/__Class_0x1c6cac0___Foo_8ccd.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x1c6cac0___Foo_aac9.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x1f6c6a0___Foo_048d.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x1fe9200___Foo_25fe.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x21a83e0___Foo_5dd5.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x21a83e0___Foo_b736.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x244dc60___Foo_cb3d.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x246ca20___Foo_f766.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x25347e0___Foo_f664.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x2551800___Foo_d751.dll +0 -0
- data/spec/ffi-inliner/cache/__Class_0x26026c0___Foo_133e.dll +0 -0
- data/spec/ffi-inliner/inliner_spec.rb +251 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +4 -0
- data/tags +201 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- metadata +120 -0
data/.gitignore
ADDED
data/History.txt
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
== 0.2.4 / 2010-06-09
|
2
|
+
|
3
|
+
* Bug fix
|
4
|
+
* Fix Issue #3: Added missing 'require' for FileUtils
|
5
|
+
* Fix Issue #5: instance variable @libraries not initialized warning
|
6
|
+
|
7
|
+
== 0.2.3 / 2009-12-07
|
8
|
+
|
9
|
+
* Minor enhancements
|
10
|
+
* Add Builder#include method to include library and user header files
|
11
|
+
* Add Builder#library method to link with custom libraries
|
12
|
+
* Add experimental support for wrapping C++ through C. When using
|
13
|
+
GPlusPlus compiler, the inliner will automatically wraps C code
|
14
|
+
inside an extern "C" block.
|
15
|
+
* Bug fix
|
16
|
+
* Fix Issue#2: TCC generated shared libraries do not work in Windows
|
17
|
+
(thanks to Luis Lavena)
|
18
|
+
* Changes in the API
|
19
|
+
* Rename #compiler in #use_compiler
|
20
|
+
* Now #compiler returns the current compiler
|
21
|
+
|
22
|
+
== 0.2.2 / 2009-08-05
|
23
|
+
|
24
|
+
* Bug fix
|
25
|
+
* Fix ffi gem version dependency issue
|
26
|
+
|
27
|
+
== 0.2.1 / 2009-08-05
|
28
|
+
|
29
|
+
* Bug fix
|
30
|
+
* Add fPIC option to gcc compiler to fix AMD64 compilation issue
|
31
|
+
|
32
|
+
== 0.2.0 / 2009-07-20
|
33
|
+
|
34
|
+
* Major enhancements
|
35
|
+
* Add support for different compiler backends
|
36
|
+
* Improve compatibility with Windows and OSX boxes
|
37
|
+
* Minor enhancements
|
38
|
+
* Add support for configuration block syntax
|
39
|
+
* Remove dependency from ffi-tcc and libtcc
|
40
|
+
* Improve compatibility with MRI 1.9.1
|
41
|
+
* Cleanup and code refactoring
|
42
|
+
|
43
|
+
== 0.1.0 / 2009-07-07
|
44
|
+
|
45
|
+
* 1 major enhancement
|
46
|
+
* Birthday!
|
47
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
ffi-inliner
|
2
|
+
by Andrea Fazzi
|
3
|
+
http://github.com/remogatto/ffi-inliner
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
With ffi-inliner you can run C code within your ruby script.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Mix C snippets in your Ruby code and gulp it on the fly!
|
12
|
+
* It's based on Ruby-FFI so the C code you inject is portable across
|
13
|
+
Ruby implementations!
|
14
|
+
* Yep, it means that you can run it on JRuby too!
|
15
|
+
* Fast compilation through tcc[http://bellard.org/tcc/]
|
16
|
+
* But it can use the system's compiler (e.g. gcc) on those platforms
|
17
|
+
that don't support tcc (e.g. OSX) or that don't have it installed
|
18
|
+
|
19
|
+
== SYNOPSIS:
|
20
|
+
|
21
|
+
require 'ffi-inliner'
|
22
|
+
|
23
|
+
module MyLib
|
24
|
+
extend Inliner
|
25
|
+
inline 'void say_hello(char* name) { printf("Hello, %s\n", name); }'
|
26
|
+
end
|
27
|
+
|
28
|
+
MyLib.say_hello('boys')
|
29
|
+
|
30
|
+
class Foo
|
31
|
+
include MyLib
|
32
|
+
end
|
33
|
+
|
34
|
+
Foo.new.say_hello('foos')
|
35
|
+
|
36
|
+
For other hints see the examples/ folder or visit the
|
37
|
+
wiki[http://wiki.github.com/remogatto/ffi-inliner/tutorial]. For a
|
38
|
+
"real" world example you may be interested to
|
39
|
+
ffi-life[http://github.com/remogatto/ffi-life].
|
40
|
+
|
41
|
+
== REQUIREMENTS:
|
42
|
+
|
43
|
+
* ffi >= 0.4.0
|
44
|
+
* gcc and/or tcc >= 0.9.25 (optional)
|
45
|
+
|
46
|
+
== DOWNLOAD/INSTALL:
|
47
|
+
|
48
|
+
From rubyforge:
|
49
|
+
|
50
|
+
[sudo] gem install ffi-inliner
|
51
|
+
|
52
|
+
or from github:
|
53
|
+
|
54
|
+
git clone git://github.com/remogatto/ffi-inliner
|
55
|
+
cd ffi-inliner
|
56
|
+
sudo rake gem:install
|
57
|
+
|
58
|
+
== CREDITS
|
59
|
+
|
60
|
+
This software is inspired to
|
61
|
+
RubyInline[http://www.zenspider.com/ZSS/Products/RubyInline/] by Ryan
|
62
|
+
Davis. Thank you Ryan.
|
63
|
+
|
64
|
+
== LICENSE:
|
65
|
+
|
66
|
+
(The MIT License)
|
67
|
+
|
68
|
+
Copyright (c) 2009 Andrea Fazzi
|
69
|
+
|
70
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
71
|
+
a copy of this software and associated documentation files (the
|
72
|
+
'Software'), to deal in the Software without restriction, including
|
73
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
74
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
75
|
+
permit persons to whom the Software is furnished to do so, subject to
|
76
|
+
the following conditions:
|
77
|
+
|
78
|
+
The above copyright notice and this permission notice shall be
|
79
|
+
included in all copies or substantial portions of the Software.
|
80
|
+
|
81
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
82
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
83
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
84
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
85
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
86
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
87
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), 'lib')))
|
6
|
+
require 'ffi-inliner/version'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'bones'
|
10
|
+
Bones.setup
|
11
|
+
rescue LoadError
|
12
|
+
begin
|
13
|
+
load 'tasks/setup.rb'
|
14
|
+
rescue LoadError
|
15
|
+
raise RuntimeError, '### please install the "bones" gem ###'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
CLOBBER << '*~' << '*.*~'
|
20
|
+
|
21
|
+
PROJ.name = 'rdp-ffi-inliner'
|
22
|
+
PROJ.authors = 'Andrea Fazzi'
|
23
|
+
PROJ.email = 'andrea.fazzi@alcacoop.it'
|
24
|
+
PROJ.url = 'http://github.com/remogatto/ffi-inliner'
|
25
|
+
PROJ.version = Inliner::VERSION
|
26
|
+
|
27
|
+
PROJ.readme_file = 'README.rdoc'
|
28
|
+
|
29
|
+
PROJ.rubyforge.name = 'ffi-inliner'
|
30
|
+
|
31
|
+
PROJ.ann.paragraphs << 'FEATURES' << 'SYNOPSIS' << 'REQUIREMENTS' << 'DOWNLOAD/INSTALL' << 'CREDITS'
|
32
|
+
PROJ.ann.email[:from] = 'andrea.fazzi@alcacoop.it'
|
33
|
+
PROJ.ann.email[:to] << 'ruby-ffi@googlegroups.com'
|
34
|
+
PROJ.ann.email[:server] = 'smtp.gmail.com'
|
35
|
+
|
36
|
+
PROJ.spec.opts << '--color' << '-fs'
|
37
|
+
|
38
|
+
PROJ.ruby_opts = []
|
39
|
+
|
40
|
+
depend_on 'ffi', '>=0.4.0'
|
41
|
+
|
42
|
+
task :default => 'spec'
|
43
|
+
|
44
|
+
# EOF
|
data/examples/ex_1.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '../lib')))
|
2
|
+
require 'ffi-inliner'
|
3
|
+
|
4
|
+
module MyLib
|
5
|
+
extend Inliner
|
6
|
+
inline 'void say_hello(char* name) { printf("Hello, %s\n", name); }'
|
7
|
+
end
|
8
|
+
|
9
|
+
MyLib.say_hello('boys')
|
10
|
+
|
11
|
+
class Foo
|
12
|
+
include MyLib
|
13
|
+
end
|
14
|
+
|
15
|
+
Foo.new.say_hello('foos')
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
data/lib/ffi-inliner.rb
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
module Inliner
|
2
|
+
|
3
|
+
DEV_NULL = if Config::CONFIG['target_os'] =~ /mswin|mingw/
|
4
|
+
'nul'
|
5
|
+
else
|
6
|
+
'/dev/null'
|
7
|
+
end
|
8
|
+
|
9
|
+
LIB_EXT = if Config::CONFIG['target_os'] =~ /darwin/
|
10
|
+
'.dylib'
|
11
|
+
elsif Config::CONFIG['target_os'] =~ /mswin|mingw/
|
12
|
+
'.dll'
|
13
|
+
else
|
14
|
+
'.so'
|
15
|
+
end
|
16
|
+
|
17
|
+
C_TO_FFI = {
|
18
|
+
'void' => :void,
|
19
|
+
'char' => :char,
|
20
|
+
'unsigned char' => :uchar,
|
21
|
+
'int' => :int,
|
22
|
+
'unsigned int' => :uint,
|
23
|
+
'long' => :long,
|
24
|
+
'unsigned long' => :ulong,
|
25
|
+
'float' => :float,
|
26
|
+
'double' => :double,
|
27
|
+
}
|
28
|
+
|
29
|
+
@@__inliner_directory = File.expand_path(File.join('~/', '.ffi-inliner'))
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def directory
|
33
|
+
@@__inliner_directory
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class FilenameManager
|
38
|
+
def initialize(mod, code, libraries)
|
39
|
+
@mod = mod.name.gsub(/[:#<>\/]/, '_')
|
40
|
+
@code = code
|
41
|
+
@libraries = libraries
|
42
|
+
end
|
43
|
+
def cached?
|
44
|
+
exists?
|
45
|
+
end
|
46
|
+
def exists?
|
47
|
+
File.exists?(c_fn)
|
48
|
+
end
|
49
|
+
def base_fn
|
50
|
+
File.join(Inliner.directory, "#{@mod}_#{(Digest::MD5.new << @code << @libraries.to_s).to_s[0, 4]}")
|
51
|
+
end
|
52
|
+
%w(c rb log).each do |ext|
|
53
|
+
define_method("#{ext}_fn") { "#{base_fn}.#{ext}" }
|
54
|
+
end
|
55
|
+
def so_fn
|
56
|
+
"#{base_fn}#{LIB_EXT}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module Compilers
|
61
|
+
class Compiler
|
62
|
+
attr_reader :progname
|
63
|
+
def self.check_and_create(fm = nil, libraries = nil)
|
64
|
+
compiler = new(fm, libraries)
|
65
|
+
unless compiler.exists?
|
66
|
+
raise "Can't find compiler #{compiler.class}"
|
67
|
+
else
|
68
|
+
compiler
|
69
|
+
end
|
70
|
+
end
|
71
|
+
def initialize(fm = nil, libraries = nil)
|
72
|
+
@fm = fm
|
73
|
+
@libraries = libraries
|
74
|
+
@progname = cmd.split.first
|
75
|
+
end
|
76
|
+
def compile
|
77
|
+
puts 'running:' + cmd if $VERBOSE
|
78
|
+
raise "Compile error! See #{@fm.log_fn}" unless system(cmd)
|
79
|
+
end
|
80
|
+
private
|
81
|
+
def libs
|
82
|
+
@libraries.inject("") { |str, lib| str << "-l#{lib} " } if @libraries
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class GCC < Compiler
|
87
|
+
def exists?
|
88
|
+
IO.popen("#{@progname} 2>&1") { |f| f.gets } ? true : false
|
89
|
+
end
|
90
|
+
def ldshared
|
91
|
+
if Config::CONFIG['target_os'] =~ /darwin/
|
92
|
+
'gcc -dynamic -bundle -fPIC'
|
93
|
+
else
|
94
|
+
'gcc -shared -fPIC'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
def cmd
|
98
|
+
"#{ldshared} #{libs} -o \"#{@fm.so_fn}\" \"#{@fm.c_fn}\" 2>\"#{@fm.log_fn}\""
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class GPlusPlus < GCC
|
103
|
+
def ldshared
|
104
|
+
if Config::CONFIG['target_os'] =~ /darwin/
|
105
|
+
'g++ -dynamic -bundle -fPIC'
|
106
|
+
elsif ENV['OS'] == 'Windows_NT'
|
107
|
+
# windows requires use of sh first
|
108
|
+
def cmd
|
109
|
+
"sh -c 'g++ -shared -fPIC #{libs} -o \"#{@fm.so_fn}\" \"#{@fm.c_fn}\"' 2>\"#{@fm.log_fn}\""
|
110
|
+
end
|
111
|
+
else
|
112
|
+
# Linux
|
113
|
+
'g++ -shared -fPIC'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class TCC < Compiler
|
119
|
+
def exists?
|
120
|
+
IO.popen("#{@progname}") { |f| f.gets } ? true : false
|
121
|
+
end
|
122
|
+
def cmd
|
123
|
+
if Config::CONFIG['target_os'] =~ /mswin|mingw/
|
124
|
+
"tcc -rdynamic -shared #{libs} -o \"#{@fm.so_fn}\" \"#{@fm.c_fn}\" 2>\"#{@fm.log_fn}\""
|
125
|
+
else
|
126
|
+
"tcc -shared #{libs} -o \"#{@fm.so_fn}\" \"#{@fm.c_fn}\" 2>\"#{@fm.log_fn}\""
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class Builder
|
133
|
+
attr_reader :code, :compiler
|
134
|
+
def initialize(mod, code = "", options = {})
|
135
|
+
make_pointer_types
|
136
|
+
@mod = mod
|
137
|
+
@code = code
|
138
|
+
@sig = [parse_signature(@code)] unless @code.empty?
|
139
|
+
options = { :use_compiler => Compilers::GCC }.merge(options)
|
140
|
+
@compiler = options[:use_compiler]
|
141
|
+
@libraries = []
|
142
|
+
end
|
143
|
+
|
144
|
+
def map(type_map)
|
145
|
+
@types.merge!(type_map)
|
146
|
+
end
|
147
|
+
|
148
|
+
def include(fn, options = {})
|
149
|
+
options[:quoted] ? @code << "#include \"#{fn}\"\n" : @code << "#include <#{fn}>\n"
|
150
|
+
end
|
151
|
+
|
152
|
+
def library(*libraries)
|
153
|
+
(@libraries ||= []).concat(libraries)
|
154
|
+
end
|
155
|
+
|
156
|
+
def c(code)
|
157
|
+
(@sig ||= []) << parse_signature(code)
|
158
|
+
@code << (@compiler == Compilers::GPlusPlus ? "extern \"C\" {\n#{code}\n}" : code )
|
159
|
+
end
|
160
|
+
|
161
|
+
def c_raw(code)
|
162
|
+
@code << code
|
163
|
+
end
|
164
|
+
|
165
|
+
def use_compiler(compiler)
|
166
|
+
@compiler = compiler
|
167
|
+
end
|
168
|
+
|
169
|
+
def struct(ffi_struct)
|
170
|
+
@code << "typedef struct {"
|
171
|
+
ffi_struct.layout.fields.each do |field|
|
172
|
+
@code << "#{field} #{field.name};\n"
|
173
|
+
end
|
174
|
+
@code << "} #{ffi_struct.class.name}"
|
175
|
+
end
|
176
|
+
|
177
|
+
def build
|
178
|
+
@fm = FilenameManager.new(@mod, @code, @libraries)
|
179
|
+
@compiler = @compiler.check_and_create(@fm, @libraries)
|
180
|
+
unless @fm.cached?
|
181
|
+
write_files(@code, @sig)
|
182
|
+
@compiler.compile
|
183
|
+
@mod.instance_eval generate_ffi(@sig)
|
184
|
+
else
|
185
|
+
@mod.instance_eval(File.read(@fm.rb_fn))
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def make_pointer_types
|
192
|
+
@types = C_TO_FFI.dup
|
193
|
+
C_TO_FFI.each_key do |k|
|
194
|
+
@types["#{k} *"] = :pointer
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def cached?(name, code)
|
199
|
+
File.exists?(cname(name, code))
|
200
|
+
end
|
201
|
+
|
202
|
+
def to_ffi_type(c_type)
|
203
|
+
@types[c_type]
|
204
|
+
end
|
205
|
+
|
206
|
+
# Based on RubyInline code by Ryan Davis
|
207
|
+
# Copyright (c) 2001-2007 Ryan Davis, Zen Spider Software
|
208
|
+
def strip_comments(code)
|
209
|
+
# strip c-comments
|
210
|
+
src = code.gsub(%r%\s*/\*.*?\*/%m, '')
|
211
|
+
# strip cpp-comments
|
212
|
+
src = src.gsub(%r%^\s*//.*?\n%, '')
|
213
|
+
src = src.gsub(%r%[ \t]*//[^\n]*%, '')
|
214
|
+
src
|
215
|
+
end
|
216
|
+
|
217
|
+
# Based on RubyInline code by Ryan Davis
|
218
|
+
# Copyright (c) 2001-2007 Ryan Davis, Zen Spider Software
|
219
|
+
def parse_signature(code)
|
220
|
+
|
221
|
+
sig = strip_comments(code)
|
222
|
+
|
223
|
+
# strip preprocessor directives
|
224
|
+
sig.gsub!(/^\s*\#.*(\\\n.*)*/, '')
|
225
|
+
# strip {}s
|
226
|
+
sig.gsub!(/\{[^\}]*\}/, '{ }')
|
227
|
+
# clean and collapse whitespace
|
228
|
+
sig.gsub!(/\s+/, ' ')
|
229
|
+
|
230
|
+
# types = 'void|int|char|char\s\*|void\s\*'
|
231
|
+
types = @types.keys.map{|x| Regexp.escape(x)}.join('|')
|
232
|
+
sig = sig.gsub(/\s*\*\s*/, ' * ').strip
|
233
|
+
|
234
|
+
if /(#{types})\s*(\w+)\s*\(([^)]*)\)/ =~ sig then
|
235
|
+
return_type, function_name, arg_string = $1, $2, $3
|
236
|
+
args = []
|
237
|
+
arg_string.split(',').each do |arg|
|
238
|
+
|
239
|
+
# helps normalize into 'char * varname' form
|
240
|
+
arg = arg.gsub(/\s*\*\s*/, ' * ').strip
|
241
|
+
|
242
|
+
if /(((#{types})\s*\*?)+)\s+(\w+)\s*$/ =~ arg then
|
243
|
+
args.push($1)
|
244
|
+
elsif arg != "void" then
|
245
|
+
warn "WAR\NING: '#{arg}' not understood"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
arity = args.size
|
250
|
+
|
251
|
+
return {
|
252
|
+
'return' => return_type,
|
253
|
+
'name' => function_name,
|
254
|
+
'args' => args,
|
255
|
+
'arity' => arity
|
256
|
+
}
|
257
|
+
end
|
258
|
+
|
259
|
+
raise SyntaxError, "Can't parse signature: #{sig}"
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
def generate_ffi(sig)
|
264
|
+
|
265
|
+
ffi_code = <<PREAMBLE
|
266
|
+
extend FFI::Library
|
267
|
+
ffi_lib '#{@fm.so_fn}'
|
268
|
+
|
269
|
+
PREAMBLE
|
270
|
+
|
271
|
+
unless sig.nil?
|
272
|
+
sig.each do |s|
|
273
|
+
args = s['args'].map { |arg| ":#{to_ffi_type(arg)}" }.join(',')
|
274
|
+
ffi_code << "attach_function '#{s['name']}', [#{args}], :#{to_ffi_type(s['return'])}\n"
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
ffi_code
|
279
|
+
end
|
280
|
+
def write_c(code)
|
281
|
+
File.open(@fm.c_fn, 'w') { |f| f << code }
|
282
|
+
end
|
283
|
+
|
284
|
+
def write_ffi(sig)
|
285
|
+
File.open(@fm.rb_fn, 'w') { |f| f << generate_ffi(sig) }
|
286
|
+
end
|
287
|
+
|
288
|
+
def write_files(code, sig)
|
289
|
+
write_c(code)
|
290
|
+
write_ffi(sig)
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
def inline(code = "", options = {})
|
296
|
+
__inliner_make_directory
|
297
|
+
builder = Builder.new(self, code, options)
|
298
|
+
yield builder if block_given?
|
299
|
+
builder.build
|
300
|
+
end
|
301
|
+
|
302
|
+
private
|
303
|
+
|
304
|
+
def __inliner_make_directory
|
305
|
+
FileUtils.mkdir(Inliner.directory) unless (File.exists?(Inliner.directory) && File.directory?(Inliner.directory))
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|