1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
# Require the main spec_helper.rb at the end to let `ruby ...spec.rb` work
# MRI magic to use built but not installed ruby
$extmk = false
require 'rbconfig'
OBJDIR ||= File.expand_path("../../../ext/#{RUBY_ENGINE}/#{RUBY_VERSION}", __FILE__)
def object_path
path = OBJDIR
if ENV['SPEC_CAPI_CXX'] == 'true'
path = "#{path}/cxx"
end
mkdir_p(path)
path
end
def compile_extension(name)
debug = false
cxx = ENV['SPEC_CAPI_CXX'] == 'true'
run_mkmf_in_process = RUBY_ENGINE == 'truffleruby'
core_ext_dir = File.expand_path("../ext", __FILE__)
spec_caller_location = caller_locations.find { |c| c.path.end_with?('_spec.rb') }
spec_file_path = spec_caller_location.path
spec_ext_dir = File.expand_path("../ext", spec_file_path)
ext = "#{name}_spec"
lib = "#{object_path}/#{ext}.#{RbConfig::CONFIG['DLEXT']}"
rubyhdrdir = RbConfig::CONFIG['rubyhdrdir']
ruby_header = "#{rubyhdrdir}/ruby.h"
abi_header = "#{rubyhdrdir}/ruby/internal/abi.h"
if RbConfig::CONFIG["ENABLE_SHARED"] == "yes"
# below is defined since 2.1, except for mswin, and maybe other platforms
libdirname = RbConfig::CONFIG.fetch 'libdirname', 'libdir'
libruby = "#{RbConfig::CONFIG[libdirname]}/#{RbConfig::CONFIG['LIBRUBY']}"
end
begin
mtime = File.mtime(lib)
rescue Errno::ENOENT
# not found, then compile
else
case # if lib is older than headers, source or libruby, then recompile
when mtime <= File.mtime("#{core_ext_dir}/rubyspec.h")
when mtime <= File.mtime("#{spec_ext_dir}/#{ext}.c")
when mtime <= File.mtime(ruby_header)
when (mtime <= File.mtime(abi_header) rescue nil)
when libruby && mtime <= File.mtime(libruby)
else
return lib # up-to-date
end
end
# Copy needed source files to tmpdir
tmpdir = tmp("cext_#{name}")
Dir.mkdir(tmpdir)
begin
["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"].each do |file|
if cxx and file.end_with?('.c')
cp file, "#{tmpdir}/#{File.basename(file, '.c')}.cpp"
else
cp file, "#{tmpdir}/#{File.basename(file)}"
end
end
Dir.chdir(tmpdir) do
if run_mkmf_in_process
required = require 'mkmf'
# Reinitialize mkmf if already required
init_mkmf unless required
create_makefile(ext, tmpdir)
else
File.write("extconf.rb", <<-RUBY)
require 'mkmf'
$ruby = ENV.values_at('RUBY_EXE', 'RUBY_FLAGS').join(' ')
# MRI magic to consider building non-bundled extensions
$extout = nil
append_cflags '-Wno-declaration-after-statement'
create_makefile(#{ext.inspect})
RUBY
output = ruby_exe("extconf.rb")
raise "extconf failed:\n#{output}" unless $?.success?
$stderr.puts output if debug
end
# Do not capture stderr as we want to show compiler warnings
make, opts = setup_make
output = IO.popen([make, "V=1", "DESTDIR=", opts], &:read)
raise "#{make} failed:\n#{output}" unless $?.success?
$stderr.puts output if debug
cp File.basename(lib), lib
end
ensure
rm_r tmpdir
end
File.chmod(0755, lib)
lib
end
def setup_make
make = ENV['MAKE']
make ||= (RbConfig::CONFIG['host_os'].include?("mswin") ? "nmake" : "make")
make_flags = ENV["MAKEFLAGS"] || ''
# suppress logo of nmake.exe to stderr
if File.basename(make, ".*").downcase == "nmake" and !make_flags.include?("l")
ENV["MAKEFLAGS"] = "l#{make_flags}"
end
opts = {}
if /(?:\A|\s)--jobserver-(?:auth|fds)=(\d+),(\d+)/ =~ make_flags
begin
r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
rescue Errno::EBADF
else
opts[r] = r
opts[w] = w
end
end
[make, opts]
end
def load_extension(name)
ext_path = compile_extension(name)
require ext_path
ext_path
rescue LoadError => e
if %r{/usr/sbin/execerror ruby "\(ld 3 1 main ([/a-zA-Z0-9_\-.]+_spec\.so)"} =~ e.message
system('/usr/sbin/execerror', "#{RbConfig::CONFIG["bindir"]}/ruby", "(ld 3 1 main #{$1}")
end
raise
end
# Constants
CAPI_SIZEOF_LONG = [0].pack('l!').size
# Require the main spec_helper.rb only here so load_extension() is defined
# when running specs with `ruby ...spec.rb`
require_relative '../../spec_helper'
|