RubyInline 3.6.2 → 3.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +15 -1
- data/Manifest.txt +3 -3
- data/README.txt +1 -2
- data/Rakefile +5 -21
- data/{inline_package → bin/inline_package} +0 -0
- data/example.rb +44 -32
- data/example2.rb +6 -1
- data/{inline.rb → lib/inline.rb} +200 -168
- data/{test_inline.rb → test/test_inline.rb} +22 -22
- metadata +13 -13
data/History.txt
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
+
*** 3.6.3 / 2007-04-27
|
2
|
+
|
3
|
+
+ 7 minor enhancements:
|
4
|
+
Added map_ruby_const and map_c_const to C builder.
|
5
|
+
Converted example.rb to a real benchmark setup.
|
6
|
+
Improved error messages.
|
7
|
+
Added options hash for all C builder methods.
|
8
|
+
Options hash can take optional :method_name param to have ruby name diff from c.
|
9
|
+
Converted to a more traditional setup. Now I can heckle!
|
10
|
+
Cleaned up ruby.h search.
|
11
|
+
+ 2 bug fixes:
|
12
|
+
Added CCDLFLAGS. _Should_ pick up -fPIC on misconfigured 64 bit machines.
|
13
|
+
Broke up all warnings so progress report was cleaner.
|
14
|
+
|
1
15
|
*** 3.6.2 / 2006-10-12
|
2
16
|
|
3
|
-
+ 2 bug fixes
|
17
|
+
+ 2 bug fixes:
|
4
18
|
+ comment stripper much more sane to fix problems on certain linux distros
|
5
19
|
+ fixed a nit with older C compilers.
|
6
20
|
|
data/Manifest.txt
CHANGED
@@ -2,12 +2,12 @@ History.txt
|
|
2
2
|
Manifest.txt
|
3
3
|
README.txt
|
4
4
|
Rakefile
|
5
|
+
bin/inline_package
|
5
6
|
demo/fastmath.rb
|
6
7
|
demo/hello.rb
|
7
8
|
example.rb
|
8
9
|
example2.rb
|
9
|
-
inline.rb
|
10
|
-
|
11
|
-
test_inline.rb
|
10
|
+
lib/inline.rb
|
11
|
+
test/test_inline.rb
|
12
12
|
tutorial/example1.rb
|
13
13
|
tutorial/example2.rb
|
data/README.txt
CHANGED
data/Rakefile
CHANGED
@@ -3,44 +3,28 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'hoe'
|
5
5
|
|
6
|
-
require './inline.rb'
|
6
|
+
require './lib/inline.rb'
|
7
7
|
|
8
8
|
Hoe.new("RubyInline", Inline::VERSION) do |p|
|
9
9
|
p.summary = "Multi-language extension coding within ruby."
|
10
10
|
p.description = p.paragraphs_of("README.txt", 3).join
|
11
|
+
p.url = p.paragraphs_of("README.txt", 1).join
|
11
12
|
p.changes = p.paragraphs_of("History.txt", 0..1).join
|
12
13
|
p.clean_globs << File.expand_path("~/.ruby_inline")
|
13
14
|
|
14
15
|
p.spec_extras[:requirements] = "A POSIX environment and a compiler for your language."
|
15
|
-
p.spec_extras[:require_paths] = ["."]
|
16
|
-
|
17
|
-
p.lib_files = %w(inline.rb)
|
18
|
-
p.test_files = %w(test_inline.rb)
|
19
|
-
p.bin_files = %w(inline_package)
|
20
16
|
end
|
21
17
|
|
22
18
|
task :examples do
|
23
19
|
%w(example.rb example2.rb tutorial/example1.rb tutorial/example2.rb).each do |e|
|
24
20
|
rm_rf '~/.ruby_inline'
|
25
|
-
ruby "-
|
21
|
+
ruby "-Ilib -w #{e}"
|
26
22
|
end
|
27
23
|
end
|
28
24
|
|
29
25
|
task :bench do
|
30
26
|
verbose(false) do
|
31
|
-
|
32
|
-
ruby "-
|
33
|
-
puts "Running primer - preloads the compiler and stuff"
|
34
|
-
rm_rf '~/.ruby_inline'
|
35
|
-
ruby "-I. ./example.rb 0"
|
36
|
-
puts "With full builds"
|
37
|
-
(0..2).each do |i|
|
38
|
-
rm_rf '~/.ruby_inline'
|
39
|
-
ruby "-I. ./example.rb #{i}"
|
40
|
-
end
|
41
|
-
puts "Without builds"
|
42
|
-
(0..2).each do |i|
|
43
|
-
ruby "-I. ./example.rb #{i}"
|
44
|
-
end
|
27
|
+
ruby "-Ilib ./example.rb"
|
28
|
+
ruby "-Ilib ./example.rb 1000000 12" # 12 is the bignum cutoff for factorial
|
45
29
|
end
|
46
30
|
end
|
File without changes
|
data/example.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
#!/usr/local/bin/ruby -w
|
2
2
|
|
3
|
-
begin
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
rescue LoadError
|
6
|
+
$: << 'lib'
|
7
|
+
end
|
4
8
|
require 'inline'
|
5
9
|
|
6
10
|
class MyTest
|
@@ -30,45 +34,53 @@ class MyTest
|
|
30
34
|
end
|
31
35
|
end
|
32
36
|
|
33
|
-
t = MyTest.new()
|
34
|
-
|
35
|
-
arg = ARGV.shift || 0
|
36
|
-
arg = arg.to_i
|
37
|
-
|
38
37
|
# breakeven for build run vs native doing 5 factorial:
|
39
38
|
# on a PIII/750 running FreeBSD: about 5000
|
40
39
|
# on a PPC/G4/800 running Mac OSX 10.2: always faster
|
41
|
-
max = ARGV.shift || 1000000
|
42
|
-
max = max.to_i
|
43
40
|
|
41
|
+
require 'benchmark'
|
44
42
|
puts "RubyInline #{Inline::VERSION}" if $DEBUG
|
45
43
|
|
46
44
|
MyTest.send(:alias_method, :factorial_alias, :factorial_c_raw)
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
t = MyTest.new()
|
47
|
+
max = (ARGV.shift || 1_000_000).to_i
|
48
|
+
n = (ARGV.shift || 5).to_i
|
49
|
+
m = t.factorial(n)
|
51
50
|
|
52
|
-
|
53
|
-
|
54
|
-
when 0 then
|
55
|
-
type = "Inline C "
|
56
|
-
(1..max).each { |m| n = t.factorial_c(5); validate(n); }
|
57
|
-
when 1 then
|
58
|
-
type = "InlineRaw"
|
59
|
-
(1..max).each { |m| n = t.factorial_c_raw(5); validate(n); }
|
60
|
-
when 2 then
|
61
|
-
type = "Alias "
|
62
|
-
(1..max).each { |m| n = t.factorial_alias(5); validate(n); }
|
63
|
-
when 3 then
|
64
|
-
type = "Native "
|
65
|
-
(1..max).each { |m| n = t.factorial(5); validate(n); }
|
66
|
-
else
|
67
|
-
$stderr.puts "ERROR: argument #{arg} not recognized"
|
68
|
-
exit(1)
|
51
|
+
def validate(n, m)
|
52
|
+
if n != m then raise "#{n} != #{m}"; end
|
69
53
|
end
|
70
|
-
tend = Time.now
|
71
54
|
|
72
|
-
|
73
|
-
|
74
|
-
|
55
|
+
puts "# of iterations = #{max}, n = #{n}"
|
56
|
+
Benchmark::bm(20) do |x|
|
57
|
+
x.report("null_time") do
|
58
|
+
for i in 0..max do
|
59
|
+
# do nothing
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
x.report("c") do
|
64
|
+
for i in 0..max do
|
65
|
+
validate(t.factorial_c(n), m)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
x.report("c-raw") do
|
70
|
+
for i in 0..max do
|
71
|
+
validate(t.factorial_c_raw(n), m)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
x.report("c-alias") do
|
76
|
+
for i in 0..max do
|
77
|
+
validate(t.factorial_alias(n), m)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
x.report("pure ruby") do
|
82
|
+
for i in 0..max do
|
83
|
+
validate(t.factorial(n), m)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/example2.rb
CHANGED
data/{inline.rb → lib/inline.rb}
RENAMED
@@ -19,9 +19,9 @@
|
|
19
19
|
# }
|
20
20
|
# end
|
21
21
|
# end
|
22
|
-
#
|
22
|
+
#
|
23
23
|
# = DESCRIPTION
|
24
|
-
#
|
24
|
+
#
|
25
25
|
# Inline allows you to write foreign code within your ruby code. It
|
26
26
|
# automatically determines if the code in question has changed and
|
27
27
|
# builds it only when necessary. The extensions are then automatically
|
@@ -51,8 +51,8 @@ class CompilationError < RuntimeError; end
|
|
51
51
|
# the current namespace.
|
52
52
|
|
53
53
|
module Inline
|
54
|
-
VERSION = '3.6.
|
55
|
-
|
54
|
+
VERSION = '3.6.3'
|
55
|
+
|
56
56
|
WINDOZE = /win32/ =~ RUBY_PLATFORM
|
57
57
|
DEV_NULL = (WINDOZE ? 'nul' : '/dev/null')
|
58
58
|
RAKE = (WINDOZE ? 'rake.cmd' : 'rake')
|
@@ -84,8 +84,8 @@ module Inline
|
|
84
84
|
directory = File.join(rootdir, ".ruby_inline")
|
85
85
|
unless defined? @@directory and directory == @@directory and test ?d, @@directory then
|
86
86
|
unless File.directory? directory then
|
87
|
-
|
88
|
-
|
87
|
+
$stderr.puts "NOTE: creating #{directory} for RubyInline" if $DEBUG
|
88
|
+
Dir.mkdir directory, 0700
|
89
89
|
end
|
90
90
|
Dir.assert_secure directory
|
91
91
|
@@directory = directory
|
@@ -97,8 +97,8 @@ module Inline
|
|
97
97
|
# Inline. It can be used as a template to write builders for other
|
98
98
|
# languages. It understands type-conversions for the basic types and
|
99
99
|
# can be extended as needed.
|
100
|
-
|
101
|
-
class C
|
100
|
+
|
101
|
+
class C
|
102
102
|
|
103
103
|
protected unless $TESTING
|
104
104
|
|
@@ -109,23 +109,23 @@ module Inline
|
|
109
109
|
'char' => [ 'NUM2CHR', 'CHR2FIX' ],
|
110
110
|
'char *' => [ 'STR2CSTR', 'rb_str_new2' ],
|
111
111
|
'double' => [ 'NUM2DBL', 'rb_float_new' ],
|
112
|
-
'int' => [ '
|
112
|
+
'int' => [ 'F'+'IX2INT', 'INT2FIX' ],
|
113
113
|
'long' => [ 'NUM2INT', 'INT2NUM' ],
|
114
114
|
'unsigned int' => [ 'NUM2UINT', 'UINT2NUM' ],
|
115
115
|
'unsigned long' => [ 'NUM2UINT', 'UINT2NUM' ],
|
116
116
|
'unsigned' => [ 'NUM2UINT', 'UINT2NUM' ],
|
117
117
|
'VALUE' => [ '', '' ],
|
118
118
|
# Can't do these converters because they conflict with the above:
|
119
|
-
# ID2SYM(x), SYM2ID(x), NUM2DBL(x),
|
119
|
+
# ID2SYM(x), SYM2ID(x), NUM2DBL(x), F\IX2UINT(x)
|
120
120
|
}
|
121
121
|
|
122
122
|
def ruby2c(type)
|
123
|
-
raise ArgumentError, "Unknown type #{type}" unless @@type_map.has_key? type
|
123
|
+
raise ArgumentError, "Unknown type #{type.inspect}" unless @@type_map.has_key? type
|
124
124
|
@@type_map[type].first
|
125
125
|
end
|
126
126
|
|
127
127
|
def c2ruby(type)
|
128
|
-
raise ArgumentError, "Unknown type #{type}" unless @@type_map.has_key? type
|
128
|
+
raise ArgumentError, "Unknown type #{type.inspect}" unless @@type_map.has_key? type
|
129
129
|
@@type_map[type].last
|
130
130
|
end
|
131
131
|
|
@@ -137,7 +137,7 @@ module Inline
|
|
137
137
|
src = src.gsub(%r%[ \t]*//[^\n]*%, '')
|
138
138
|
src
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
def parse_signature(src, raw=false)
|
142
142
|
|
143
143
|
sig = self.strip_comments(src)
|
@@ -153,29 +153,29 @@ module Inline
|
|
153
153
|
end
|
154
154
|
|
155
155
|
if /(#{@types})\s*(\w+)\s*\(([^)]*)\)/ =~ sig then
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
156
|
+
return_type, function_name, arg_string = $1, $2, $3
|
157
|
+
args = []
|
158
|
+
arg_string.split(',').each do |arg|
|
159
|
+
|
160
|
+
# helps normalize into 'char * varname' form
|
161
|
+
arg = arg.gsub(/\s*\*\s*/, ' * ').strip
|
162
|
+
|
163
|
+
if /(((#{@types})\s*\*?)+)\s+(\w+)\s*$/ =~ arg then
|
164
|
+
args.push([$4, $1])
|
165
|
+
elsif arg != "void" then
|
166
|
+
$stderr.puts "WAR\NING: '#{arg}' not understood"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
arity = args.size
|
171
|
+
arity = MAGIC_ARITY if raw
|
172
|
+
|
173
|
+
return {
|
174
|
+
'return' => return_type,
|
175
|
+
'name' => function_name,
|
176
|
+
'args' => args,
|
177
|
+
'arity' => arity
|
178
|
+
}
|
179
179
|
end
|
180
180
|
|
181
181
|
raise SyntaxError, "Can't parse signature: #{sig}"
|
@@ -190,46 +190,47 @@ module Inline
|
|
190
190
|
|
191
191
|
signature = parse_signature(src, !expand_types)
|
192
192
|
function_name = signature['name']
|
193
|
+
method_name = options[:method_name] || function_name
|
193
194
|
return_type = signature['return']
|
194
195
|
arity = signature['arity']
|
195
196
|
|
196
197
|
raise ArgumentError, "too many arguments" if arity > MAGIC_ARITY_THRESHOLD
|
197
198
|
|
198
199
|
if expand_types then
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
200
|
+
prefix = "static VALUE #{function_name}("
|
201
|
+
if arity == MAGIC_ARITY then
|
202
|
+
prefix += "int argc, VALUE *argv, VALUE self"
|
203
|
+
else
|
204
|
+
prefix += "VALUE self"
|
204
205
|
prefix += signature['args'].map { |arg, type| ", VALUE _#{arg}"}.join
|
205
|
-
|
206
|
-
|
206
|
+
end
|
207
|
+
prefix += ") {\n"
|
207
208
|
prefix += signature['args'].map { |arg, type|
|
208
209
|
" #{type} #{arg} = #{ruby2c(type)}(_#{arg});\n"
|
209
210
|
}.join
|
210
211
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
212
|
+
# replace the function signature (hopefully) with new sig (prefix)
|
213
|
+
result.sub!(/[^;\/\"\>]+#{function_name}\s*\([^\{]+\{/, "\n" + prefix)
|
214
|
+
result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
|
215
|
+
unless return_type == "void" then
|
216
|
+
raise SyntaxError, "Couldn't find return statement for #{function_name}" unless
|
217
|
+
result =~ /return/
|
218
|
+
result.gsub!(/return\s+([^\;\}]+)/) do
|
219
|
+
"return #{c2ruby(return_type)}(#{$1})"
|
220
|
+
end
|
221
|
+
else
|
222
|
+
result.sub!(/\s*\}\s*\Z/, "\nreturn Qnil;\n}")
|
223
|
+
end
|
223
224
|
else
|
224
|
-
|
225
|
-
|
226
|
-
|
225
|
+
prefix = "static #{return_type} #{function_name}("
|
226
|
+
result.sub!(/[^;\/\"\>]+#{function_name}\s*\(/, prefix)
|
227
|
+
result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
|
227
228
|
end
|
228
229
|
|
229
230
|
delta = if result =~ /\A(static.*?\{)/m then
|
230
231
|
$1.split(/\n/).size
|
231
232
|
else
|
232
|
-
warn "
|
233
|
+
warn "WAR\NING: Can't find signature in #{result.inspect}\n" unless $TESTING
|
233
234
|
0
|
234
235
|
end
|
235
236
|
|
@@ -237,7 +238,7 @@ module Inline
|
|
237
238
|
result = "# line #{line.to_i + delta} \"#{file}\"\n" + result unless $DEBUG and not $TESTING
|
238
239
|
|
239
240
|
@src << result
|
240
|
-
@sig[function_name] = [arity,singleton]
|
241
|
+
@sig[function_name] = [arity,singleton,method_name]
|
241
242
|
|
242
243
|
return result if $TESTING
|
243
244
|
end # def generate
|
@@ -291,7 +292,7 @@ module Inline
|
|
291
292
|
file = File.join("inline", File.basename(so_name))
|
292
293
|
if require file then
|
293
294
|
dir = Inline.directory
|
294
|
-
warn "
|
295
|
+
warn "WAR\NING: #{dir} exists but is not being used" if test ?d, dir
|
295
296
|
return true
|
296
297
|
end
|
297
298
|
rescue LoadError
|
@@ -313,21 +314,21 @@ module Inline
|
|
313
314
|
so_name = self.so_name
|
314
315
|
so_exists = File.file? so_name
|
315
316
|
unless so_exists and File.mtime(rb_file) < File.mtime(so_name)
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
317
|
+
|
318
|
+
src_name = "#{Inline.directory}/#{module_name}.c"
|
319
|
+
old_src_name = "#{src_name}.old"
|
320
|
+
should_compare = File.write_with_backup(src_name) do |io|
|
321
|
+
io.puts
|
322
|
+
io.puts "#include \"ruby.h\""
|
323
|
+
io.puts
|
324
|
+
io.puts @src.join("\n\n")
|
325
|
+
io.puts
|
326
|
+
io.puts
|
327
|
+
io.puts "#ifdef __cplusplus"
|
328
|
+
io.puts "extern \"C\" {"
|
329
|
+
io.puts "#endif"
|
329
330
|
io.puts " __declspec(dllexport)" if WINDOZE
|
330
|
-
|
331
|
+
io.puts " void Init_#{module_name}() {"
|
331
332
|
io.puts " VALUE c = rb_cObject;"
|
332
333
|
|
333
334
|
# TODO: use rb_class2path
|
@@ -335,71 +336,53 @@ module Inline
|
|
335
336
|
" c = rb_const_get_at(c,rb_intern(\"#{n}\"));"
|
336
337
|
}.join("\n")
|
337
338
|
|
338
|
-
|
339
|
-
|
339
|
+
@sig.keys.sort.each do |name|
|
340
|
+
arity, singleton, method_name = @sig[name]
|
340
341
|
if singleton then
|
341
|
-
io.print " rb_define_singleton_method(c, \"#{
|
342
|
+
io.print " rb_define_singleton_method(c, \"#{method_name}\", "
|
342
343
|
else
|
343
|
-
|
344
|
+
io.print " rb_define_method(c, \"#{method_name}\", "
|
344
345
|
end
|
345
|
-
|
346
|
-
|
347
|
-
|
346
|
+
io.puts "(VALUE(*)(ANYARGS))#{name}, #{arity});"
|
347
|
+
end
|
348
348
|
io.puts @init_extra.join("\n") unless @init_extra.empty?
|
349
349
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
350
|
+
io.puts
|
351
|
+
io.puts " }"
|
352
|
+
io.puts "#ifdef __cplusplus"
|
353
|
+
io.puts "}"
|
354
|
+
io.puts "#endif"
|
355
|
+
io.puts
|
356
|
+
end
|
357
|
+
|
358
|
+
# recompile only if the files are different
|
359
|
+
recompile = true
|
360
|
+
if so_exists and should_compare and
|
361
361
|
File::compare(old_src_name, src_name, $DEBUG) then
|
362
|
-
|
362
|
+
recompile = false
|
363
363
|
|
364
|
-
|
365
|
-
|
366
|
-
|
364
|
+
# Updates the timestamps on all the generated/compiled files.
|
365
|
+
# Prevents us from entering this conditional unless the source
|
366
|
+
# file changes again.
|
367
367
|
t = Time.now
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
elsif File.exist? srcdir + "/ruby.h" then
|
379
|
-
hdrdir = srcdir
|
380
|
-
else
|
381
|
-
$stderr.puts "ERROR: Can't find header files for ruby. Exiting..."
|
382
|
-
exit 1
|
383
|
-
end
|
384
|
-
|
385
|
-
flags = @flags.join(' ')
|
386
|
-
libs = @libs.join(' ')
|
387
|
-
|
388
|
-
cmd = "#{Config::CONFIG['LDSHARED']} #{flags} #{Config::CONFIG['CFLAGS']} -I #{hdrdir} -o \"#{so_name}\" \"#{File.expand_path(src_name)}\" #{libs}"
|
389
|
-
|
390
|
-
# gawd windoze land sucks
|
391
|
-
case RUBY_PLATFORM
|
392
|
-
when /mswin32/ then
|
393
|
-
cmd += " -link /LIBPATH:\"#{Config::CONFIG['libdir']}\" /DEFAULTLIB:\"#{Config::CONFIG['LIBRUBY']}\" /INCREMENTAL:no /EXPORT:Init_#{module_name}"
|
394
|
-
when /mingw32/ then
|
395
|
-
cmd += " -Wl,--enable-auto-import -L#{Config::CONFIG['libdir']} -lmsvcrt-ruby18"
|
396
|
-
when /i386-cygwin/ then
|
397
|
-
cmd += ' -L/usr/local/lib -lruby.dll'
|
398
|
-
end
|
368
|
+
File.utime(t, t, src_name, old_src_name, so_name)
|
369
|
+
end
|
370
|
+
|
371
|
+
if recompile then
|
372
|
+
|
373
|
+
hdrdir = %w(srcdir archdir).map { |name|
|
374
|
+
dir = Config::CONFIG[name]
|
375
|
+
}.find { |dir|
|
376
|
+
dir and File.exist? File.join(dir, "/ruby.h")
|
377
|
+
} or abort "ERROR: Can't find header dir for ruby. Exiting..."
|
399
378
|
|
379
|
+
flags = @flags.join(' ')
|
380
|
+
libs = @libs.join(' ')
|
381
|
+
|
382
|
+
cmd = "#{Config::CONFIG['LDSHARED']} #{flags} #{Config::CONFIG['CCDLFLAGS']} #{Config::CONFIG['CFLAGS']} -I #{hdrdir} -I #{Config::CONFIG['includedir']} -o \"#{so_name}\" \"#{File.expand_path(src_name)}\" #{libs}" + crap_for_windoze
|
400
383
|
cmd += " 2> #{DEV_NULL}" if $TESTING and not $DEBUG
|
401
|
-
|
402
|
-
|
384
|
+
|
385
|
+
$stderr.puts "Building #{so_name} with '#{cmd}'" if $DEBUG
|
403
386
|
result = `#{cmd}`
|
404
387
|
$stderr.puts "Output:\n#{result}" if $DEBUG
|
405
388
|
if $? != 0 then
|
@@ -420,19 +403,36 @@ module Inline
|
|
420
403
|
end
|
421
404
|
end
|
422
405
|
|
423
|
-
|
424
|
-
|
406
|
+
$stderr.puts "Built successfully" if $DEBUG
|
407
|
+
end
|
425
408
|
|
426
409
|
else
|
427
|
-
|
410
|
+
$stderr.puts "#{so_name} is up to date" if $DEBUG
|
428
411
|
end # unless (file is out of date)
|
429
412
|
end # def build
|
430
|
-
|
413
|
+
|
414
|
+
##
|
415
|
+
# Returns extra compilation flags for windoze platforms. Ugh.
|
416
|
+
|
417
|
+
def crap_for_windoze
|
418
|
+
# gawd windoze land sucks
|
419
|
+
case RUBY_PLATFORM
|
420
|
+
when /mswin32/ then
|
421
|
+
" -link /LIBPATH:\"#{Config::CONFIG['libdir']}\" /DEFAULTLIB:\"#{Config::CONFIG['LIBRUBY']}\" /INCREMENTAL:no /EXPORT:Init_#{module_name}"
|
422
|
+
when /mingw32/ then
|
423
|
+
" -Wl,--enable-auto-import -L#{Config::CONFIG['libdir']} -lmsvcrt-ruby18"
|
424
|
+
when /i386-cygwin/ then
|
425
|
+
' -L/usr/local/lib -lruby.dll'
|
426
|
+
else
|
427
|
+
''
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
431
|
##
|
432
432
|
# Adds compiler options to the compiler command line. No
|
433
433
|
# preprocessing is done, so you must have all your dashes and
|
434
434
|
# everything.
|
435
|
-
|
435
|
+
|
436
436
|
def add_compile_flags(*flags)
|
437
437
|
@flags.push(*flags)
|
438
438
|
end
|
@@ -440,7 +440,7 @@ module Inline
|
|
440
440
|
##
|
441
441
|
# Adds linker flags to the link command line. No preprocessing is
|
442
442
|
# done, so you must have all your dashes and everything.
|
443
|
-
|
443
|
+
|
444
444
|
def add_link_flags(*flags)
|
445
445
|
@libs.push(*flags)
|
446
446
|
end
|
@@ -454,61 +454,93 @@ module Inline
|
|
454
454
|
|
455
455
|
##
|
456
456
|
# Registers C type-casts +r2c+ and +c2r+ for +type+.
|
457
|
-
|
457
|
+
|
458
458
|
def add_type_converter(type, r2c, c2r)
|
459
|
-
$stderr.puts "
|
459
|
+
$stderr.puts "WAR\NING: overridding #{type} on #{caller[0]}" if @@type_map.has_key? type
|
460
460
|
@@type_map[type] = [r2c, c2r]
|
461
461
|
end
|
462
462
|
|
463
|
+
##
|
464
|
+
# Maps a ruby constant to C (with the same name)
|
465
|
+
|
466
|
+
def map_ruby_const(*names)
|
467
|
+
names.each do |name|
|
468
|
+
self.prefix "static VALUE #{name};"
|
469
|
+
self.add_to_init " #{name} = rb_const_get(c, rb_intern(#{name.to_s.inspect}));"
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
##
|
474
|
+
# Maps a C constant to ruby (with the same
|
475
|
+
# name). +names_and_types+ is a hash that maps the name of the
|
476
|
+
# constant to its C type.
|
477
|
+
|
478
|
+
def map_c_const(names_and_types)
|
479
|
+
names_and_types.each do |name, typ|
|
480
|
+
self.add_to_init " rb_define_const(c, #{name.to_s.inspect}, #{c2ruby(typ.to_s)}(#{name}));"
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
463
484
|
##
|
464
485
|
# Adds an include to the top of the file. Don't forget to use
|
465
486
|
# quotes or angle brackets.
|
466
|
-
|
487
|
+
|
467
488
|
def include(header)
|
468
489
|
@src << "#include #{header}"
|
469
490
|
end
|
470
491
|
|
471
492
|
##
|
472
493
|
# Adds any amount of text/code to the source
|
473
|
-
|
494
|
+
|
474
495
|
def prefix(code)
|
475
496
|
@src << code
|
476
497
|
end
|
477
498
|
|
478
499
|
##
|
479
500
|
# Adds a C function to the source, including performing automatic
|
480
|
-
# type conversion to arguments and the return value.
|
481
|
-
#
|
482
|
-
|
483
|
-
|
484
|
-
|
501
|
+
# type conversion to arguments and the return value. The Ruby
|
502
|
+
# method name can be overridden by providing method_name. Unknown
|
503
|
+
# type conversions can be extended by using +add_type_converter+.
|
504
|
+
|
505
|
+
def c src, options = {}
|
506
|
+
options = {
|
507
|
+
:expand_types => true,
|
508
|
+
}.merge options
|
509
|
+
self.generate src, options
|
485
510
|
end
|
486
511
|
|
487
512
|
##
|
488
513
|
# Same as +c+, but adds a class function.
|
489
|
-
|
490
|
-
def c_singleton src
|
491
|
-
|
514
|
+
|
515
|
+
def c_singleton src, options = {}
|
516
|
+
options = {
|
517
|
+
:expand_types => true,
|
518
|
+
:singleton => true,
|
519
|
+
}.merge options
|
520
|
+
self.generate src, options
|
492
521
|
end
|
493
|
-
|
522
|
+
|
494
523
|
##
|
495
524
|
# Adds a raw C function to the source. This version does not
|
496
525
|
# perform any type conversion and must conform to the ruby/C
|
497
|
-
# coding conventions.
|
498
|
-
|
499
|
-
|
500
|
-
|
526
|
+
# coding conventions. The Ruby method name can be overridden
|
527
|
+
# by providing method_name.
|
528
|
+
|
529
|
+
def c_raw src, options = {}
|
530
|
+
self.generate src, options
|
501
531
|
end
|
502
532
|
|
503
533
|
##
|
504
534
|
# Same as +c_raw+, but adds a class function.
|
505
|
-
|
506
|
-
def c_raw_singleton src
|
507
|
-
|
535
|
+
|
536
|
+
def c_raw_singleton src, options = {}
|
537
|
+
options = {
|
538
|
+
:singleton => true,
|
539
|
+
}.merge options
|
540
|
+
self.generate src, options
|
508
541
|
end
|
509
542
|
|
510
543
|
end # class Inline::C
|
511
|
-
|
512
544
|
class Packager
|
513
545
|
attr_accessor :name, :version, :summary, :libs_copied, :inline_dir
|
514
546
|
|
@@ -548,7 +580,7 @@ module Inline
|
|
548
580
|
return
|
549
581
|
end
|
550
582
|
|
551
|
-
rakefile = eval RAKEFILE_TEMPLATE
|
583
|
+
rakefile = eval RAKEFILE_TEMPLATE
|
552
584
|
|
553
585
|
STDERR.puts "==> Generating Rakefile" unless $TESTING
|
554
586
|
File.open 'Rakefile', 'w' do |fp|
|
@@ -561,7 +593,7 @@ module Inline
|
|
561
593
|
|
562
594
|
cmd = "#{RAKE} package"
|
563
595
|
cmd += "> #{DEV_NULL} 2> #{DEV_NULL}" if $TESTING unless $DEBUG
|
564
|
-
|
596
|
+
|
565
597
|
if system cmd then
|
566
598
|
unless $TESTING then
|
567
599
|
STDERR.puts
|
@@ -576,7 +608,7 @@ module Inline
|
|
576
608
|
unless defined? @gem_libs then
|
577
609
|
@gem_libs = Dir.glob File.join(@inline_dir, "*.#{@ext}")
|
578
610
|
files = Dir.glob(File.join('lib', '*')).select { |f| test ?f, f }
|
579
|
-
|
611
|
+
|
580
612
|
@gem_libs.push(*files)
|
581
613
|
@gem_libs.sort!
|
582
614
|
end
|
@@ -599,11 +631,11 @@ class Module
|
|
599
631
|
# Extends the Module class to have an inline method. The default
|
600
632
|
# language/builder used is C, but can be specified with the +lang+
|
601
633
|
# parameter.
|
602
|
-
|
634
|
+
|
603
635
|
def inline(lang = :C, options={})
|
604
636
|
case options
|
605
637
|
when TrueClass, FalseClass then
|
606
|
-
warn "
|
638
|
+
warn "WAR\NING: 2nd argument to inline is now a hash, changing to {:testing=>#{options}}" unless options
|
607
639
|
options = { :testing => options }
|
608
640
|
when Hash
|
609
641
|
options[:testing] ||= false
|
@@ -637,9 +669,9 @@ class File
|
|
637
669
|
##
|
638
670
|
# Equivalent to +File::open+ with an associated block, but moves
|
639
671
|
# any existing file with the same name to the side first.
|
640
|
-
|
672
|
+
|
641
673
|
def self.write_with_backup(path) # returns true if file already existed
|
642
|
-
|
674
|
+
|
643
675
|
# move previous version to the side if it exists
|
644
676
|
renamed = false
|
645
677
|
if test ?f, path then
|
@@ -662,15 +694,15 @@ class Dir
|
|
662
694
|
# writable permissions. If not, it prints an error and exits. It
|
663
695
|
# only works on +POSIX+ systems. Patches for other systems are
|
664
696
|
# welcome.
|
665
|
-
|
697
|
+
|
666
698
|
def self.assert_secure(path)
|
667
699
|
mode = File.stat(path).mode
|
668
700
|
unless ((mode % 01000) & 0022) == 0 then
|
669
701
|
if $TESTING then
|
670
|
-
|
702
|
+
raise SecurityError, "Directory #{path} is insecure"
|
671
703
|
else
|
672
|
-
|
673
|
-
|
704
|
+
$stderr.puts "#{path} is insecure (#{'%o' % mode}). It may not be group or world writable. Exiting."
|
705
|
+
exit 1
|
674
706
|
end
|
675
707
|
end
|
676
708
|
end
|
@@ -30,7 +30,7 @@ class InlineTestCase < Test::Unit::TestCase
|
|
30
30
|
|
31
31
|
def teardown
|
32
32
|
unless $DEBUG then
|
33
|
-
FileUtils.rm_rf @rootdir
|
33
|
+
FileUtils.rm_rf @rootdir
|
34
34
|
ENV.delete 'INLINEDIR'
|
35
35
|
end
|
36
36
|
end
|
@@ -178,7 +178,7 @@ class TestC < InlineTestCase
|
|
178
178
|
|
179
179
|
@builder.add_type_converter t, a, b unless t.nil?
|
180
180
|
result = @builder.parse_signature(src)
|
181
|
-
|
181
|
+
|
182
182
|
assert_equal(expected, result)
|
183
183
|
end
|
184
184
|
|
@@ -198,16 +198,16 @@ class TestC < InlineTestCase
|
|
198
198
|
'return' => 'int',
|
199
199
|
'arity' => 2,
|
200
200
|
'args' => [
|
201
|
-
|
202
|
-
|
201
|
+
['x', 'int'],
|
202
|
+
['y', 'int']
|
203
203
|
]
|
204
204
|
}
|
205
|
-
|
205
|
+
|
206
206
|
util_parse_signature(src, expected)
|
207
207
|
end
|
208
|
-
|
208
|
+
|
209
209
|
def test_parse_signature_custom
|
210
|
-
|
210
|
+
|
211
211
|
src = "// stupid cpp comment
|
212
212
|
#include \"header.h\"
|
213
213
|
/* stupid c comment */
|
@@ -217,19 +217,19 @@ class TestC < InlineTestCase
|
|
217
217
|
return result;
|
218
218
|
}
|
219
219
|
"
|
220
|
-
|
220
|
+
|
221
221
|
expected = {
|
222
222
|
'name' => 'add',
|
223
223
|
'return' => 'int',
|
224
224
|
'arity' => 2,
|
225
225
|
'args' => [
|
226
|
-
|
227
|
-
|
226
|
+
[ 'x', 'fooby' ],
|
227
|
+
['y', 'int']
|
228
228
|
]
|
229
229
|
}
|
230
|
-
|
230
|
+
|
231
231
|
util_parse_signature(src, expected,
|
232
|
-
|
232
|
+
"fooby", "r2c_fooby", "c2r_fooby")
|
233
233
|
end
|
234
234
|
|
235
235
|
def test_parse_signature_register
|
@@ -249,14 +249,14 @@ class TestC < InlineTestCase
|
|
249
249
|
'return' => 'int',
|
250
250
|
'arity' => 2,
|
251
251
|
'args' => [
|
252
|
-
|
253
|
-
|
252
|
+
[ 'x', 'register int' ],
|
253
|
+
['y', 'int']
|
254
254
|
]
|
255
255
|
}
|
256
256
|
|
257
|
-
|
257
|
+
|
258
258
|
util_parse_signature(src, expected,
|
259
|
-
|
259
|
+
"register int", 'FIX2INT', 'INT2FIX')
|
260
260
|
end
|
261
261
|
|
262
262
|
def util_generate(src, expected, expand_types=true)
|
@@ -532,7 +532,7 @@ puts(s); return rb_str_new2(s)}"
|
|
532
532
|
|
533
533
|
def test_build_bad
|
534
534
|
code = util_simple_code(:DumbTest2, "void should_puke() { 1+1 2+2 }")
|
535
|
-
assert_raises(CompilationError) do
|
535
|
+
assert_raises(CompilationError) do
|
536
536
|
util_test_build(code) do
|
537
537
|
flunk
|
538
538
|
end
|
@@ -650,7 +650,7 @@ class TestModule < InlineTestCase
|
|
650
650
|
|
651
651
|
def test_argument_check_fewer
|
652
652
|
fb = Foo::Bar.new
|
653
|
-
|
653
|
+
|
654
654
|
assert_raise(ArgumentError) do
|
655
655
|
assert_equal 13, fb.arity6(1, 2, 3)
|
656
656
|
end
|
@@ -668,12 +668,12 @@ class TestModule < InlineTestCase
|
|
668
668
|
builder.c "int add(int a, int b) { return a + b; }"
|
669
669
|
end
|
670
670
|
assert(test(?d, Inline.directory),
|
671
|
-
|
671
|
+
"inline dir should have been created")
|
672
672
|
matches = Dir[File.join(Inline.directory, "Inline_TestModule_*.c")]
|
673
673
|
assert_equal(1, matches.length, "Source should have been created")
|
674
674
|
library_file = matches.first.gsub(/\.c$/) { "." + Config::CONFIG["DLEXT"] }
|
675
675
|
assert(test(?f, library_file),
|
676
|
-
|
676
|
+
"Library file should have been created")
|
677
677
|
end
|
678
678
|
|
679
679
|
end
|
@@ -721,7 +721,7 @@ class TestInlinePackager < InlineTestCase
|
|
721
721
|
@packager.package
|
722
722
|
end
|
723
723
|
end
|
724
|
-
|
724
|
+
|
725
725
|
def test_copy_libs
|
726
726
|
assert_equal false, @packager.libs_copied
|
727
727
|
|
@@ -744,7 +744,7 @@ class TestInlinePackager < InlineTestCase
|
|
744
744
|
def test_generate_rakefile_has_rakefile
|
745
745
|
FileUtils.rm 'Rakefile' if test ?f, 'Rakefile' and $DEBUG
|
746
746
|
FileUtils.touch 'Rakefile'
|
747
|
-
|
747
|
+
|
748
748
|
@packager.generate_rakefile
|
749
749
|
|
750
750
|
assert_equal "", File.read('Rakefile')
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.0
|
2
|
+
rubygems_version: 0.9.0.9
|
3
3
|
specification_version: 1
|
4
4
|
name: RubyInline
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 3.6.
|
7
|
-
date:
|
6
|
+
version: 3.6.3
|
7
|
+
date: 2007-04-27 00:00:00 -07:00
|
8
8
|
summary: Multi-language extension coding within ruby.
|
9
9
|
require_paths:
|
10
|
-
-
|
10
|
+
- lib
|
11
11
|
email: ryand-ruby@zenspider.com
|
12
|
-
homepage: http://
|
12
|
+
homepage: " http://rubyforge.org/projects/rubyinline/\n"
|
13
13
|
rubyforge_project: rubyinline
|
14
14
|
description: Ruby Inline is an analog to Perl's Inline::C. Out of the box, it allows you to embed C/++ external module code in your ruby script directly. By writing simple builder classes, you can teach how to cope with new languages (fortran, perl, whatever). The code is compiled and run on the fly when needed.
|
15
15
|
autorequire:
|
@@ -33,23 +33,23 @@ files:
|
|
33
33
|
- Manifest.txt
|
34
34
|
- README.txt
|
35
35
|
- Rakefile
|
36
|
+
- bin/inline_package
|
36
37
|
- demo/fastmath.rb
|
37
38
|
- demo/hello.rb
|
38
39
|
- example.rb
|
39
40
|
- example2.rb
|
40
|
-
- inline.rb
|
41
|
-
-
|
42
|
-
- test_inline.rb
|
41
|
+
- lib/inline.rb
|
42
|
+
- test/test_inline.rb
|
43
43
|
- tutorial/example1.rb
|
44
44
|
- tutorial/example2.rb
|
45
|
-
test_files:
|
46
|
-
|
45
|
+
test_files:
|
46
|
+
- test/test_inline.rb
|
47
47
|
rdoc_options: []
|
48
48
|
|
49
49
|
extra_rdoc_files: []
|
50
50
|
|
51
|
-
executables:
|
52
|
-
|
51
|
+
executables:
|
52
|
+
- inline_package
|
53
53
|
extensions: []
|
54
54
|
|
55
55
|
requirements:
|
@@ -62,5 +62,5 @@ dependencies:
|
|
62
62
|
requirements:
|
63
63
|
- - ">="
|
64
64
|
- !ruby/object:Gem::Version
|
65
|
-
version: 1.
|
65
|
+
version: 1.2.0
|
66
66
|
version:
|