def build
so_name = self.so_name
so_exists = File.file? so_name
unless so_exists and File.mtime(rb_file) < File.mtime(so_name) then
unless File.directory? Inline.directory then
warn "NOTE: creating #{Inline.directory} for RubyInline" if $DEBUG
Dir.mkdir Inline.directory, 0700
end
src_name = "#{Inline.directory}/#{module_name}.c"
old_src_name = "#{src_name}.old"
should_compare = File.write_with_backup(src_name) do |io|
if @include_ruby_first
@inc.unshift "#include \"ruby.h\""
else
@inc.push "#include \"ruby.h\""
end
io.puts
io.puts @inc.join("\n")
io.puts
io.puts @src.join("\n\n")
io.puts
io.puts
io.puts "#ifdef __cplusplus"
io.puts "extern \"C\" {"
io.puts "#endif"
io.puts " __declspec(dllexport)" if WINDOZE
io.puts " void Init_#{module_name}() {"
io.puts " VALUE c = rb_cObject;"
io.puts @mod.name.split("::").map { |n|
" c = rb_const_get_at(c,rb_intern(\"#{n}\"));"
}.join("\n")
@sig.keys.sort.each do |name|
arity, singleton, method_name = @sig[name]
if singleton then
io.print " rb_define_singleton_method(c, \"#{method_name}\", "
else
io.print " rb_define_method(c, \"#{method_name}\", "
end
io.puts "(VALUE(*)(ANYARGS))#{name}, #{arity});"
end
io.puts @init_extra.join("\n") unless @init_extra.empty?
io.puts
io.puts " }"
io.puts "#ifdef __cplusplus"
io.puts "}"
io.puts "#endif"
io.puts
end
recompile = true
if so_exists and should_compare and
FileUtils.compare_file(old_src_name, src_name) then
recompile = false
t = Time.now
File.utime(t, t, src_name, old_src_name, so_name)
end
if recompile then
hdrdir = %w(srcdir archdir rubyhdrdir).map { |name|
dir = Config::CONFIG[name]
}.find { |dir|
dir and File.exist? File.join(dir, "/ruby.h")
} or abort "ERROR: Can't find header dir for ruby. Exiting..."
flags = @flags.join(' ')
libs = @libs.join(' ')
config_hdrdir = if RUBY_VERSION > '1.9' then
"-I #{File.join hdrdir, RbConfig::CONFIG['arch']}"
else
nil
end
cmd = [ Config::CONFIG['LDSHARED'],
flags,
Config::CONFIG['CCDLFLAGS'],
Config::CONFIG['CFLAGS'],
'-I', hdrdir,
config_hdrdir,
'-I', Config::CONFIG['includedir'],
"-L#{Config::CONFIG['libdir']}",
'-o', so_name.inspect,
File.expand_path(src_name).inspect,
libs,
crap_for_windoze ].join(' ')
cmd += ' -flat_namespace -undefined suppress' if
RUBY_PLATFORM =~ /darwin9\.[01]/
cmd += " 2> #{DEV_NULL}" if $TESTING and not $DEBUG
warn "Building #{so_name} with '#{cmd}'" if $DEBUG
result = `#{cmd}`
warn "Output:\n#{result}" if $DEBUG
if $? != 0 then
bad_src_name = src_name + ".bad"
File.rename src_name, bad_src_name
raise CompilationError, "error executing #{cmd}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
end
if WINDOZE and RUBY_PLATFORM =~ /_80$/ then
Dir.chdir Inline.directory do
cmd = "mt /manifest lib.so.manifest /outputresource:so.dll;#2"
warn "Embedding manifest with '#{cmd}'" if $DEBUG
result = `#{cmd}`
warn "Output:\n#{result}" if $DEBUG
if $? != 0 then
raise CompilationError, "error executing #{cmd}: #{$?}"
end
end
end
warn "Built successfully" if $DEBUG
end
else
warn "#{so_name} is up to date" if $DEBUG
end
end