summaryrefslogtreecommitdiff
path: root/spec/ruby/optional/capi/spec_helper.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/optional/capi/spec_helper.rb')
-rw-r--r--spec/ruby/optional/capi/spec_helper.rb134
1 files changed, 95 insertions, 39 deletions
diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb
index 373012a869..49ce23d874 100644
--- a/spec/ruby/optional/capi/spec_helper.rb
+++ b/spec/ruby/optional/capi/spec_helper.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+# 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
@@ -6,43 +6,69 @@ $extmk = false
require 'rbconfig'
OBJDIR ||= File.expand_path("../../../ext/#{RUBY_ENGINE}/#{RUBY_VERSION}", __FILE__)
-mkdir_p(OBJDIR)
-
-def extension_path
- File.expand_path("../ext", __FILE__)
-end
def object_path
- OBJDIR
+ 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']}"
- ruby_header = "#{RbConfig::CONFIG['rubyhdrdir']}/ruby.h"
- libruby_so = RbConfig::CONFIG['LIBRUBY_SO']
- ruby_library = "#{RbConfig::CONFIG['libdir']}/#{libruby_so}"
- unless libruby_so and File.exist?(ruby_library)
- # Statically-compiled lib in the binary, ignore this check
- ruby_library = nil
+ 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
- return lib if File.exist?(lib) and
- File.mtime(lib) > File.mtime("#{extension_path}/rubyspec.h") and
- File.mtime(lib) > File.mtime("#{extension_path}/#{ext}.c") and
- File.mtime(lib) > File.mtime(ruby_header) and
- (!ruby_library || File.mtime(lib) > File.mtime(ruby_library)) and
- true # sentinel
+ 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
- ["rubyspec.h", "#{ext}.c"].each do |file|
- cp "#{extension_path}/#{file}", "#{tmpdir}/#{file}"
+ files = ["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"]
+ if spec_ext_dir != core_ext_dir
+ files += Dir.glob("#{spec_ext_dir}/*.h")
+ end
+ files.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
@@ -52,11 +78,27 @@ def compile_extension(name)
init_mkmf unless required
create_makefile(ext, tmpdir)
else
- File.write("extconf.rb", "require 'mkmf'\n" +
- "$ruby = ENV.values_at('RUBY_EXE', 'RUBY_FLAGS').join(' ')\n" +
+ # Workaround for digest C-API specs to find the ruby/digest.h header
+ # when run in the CRuby repository via make test-spec
+ if MSpecScript.instance_variable_defined?(:@testing_ruby)
+ ruby_repository_extra_include_dir = "-I#{RbConfig::CONFIG.fetch("prefix")}/#{RbConfig::CONFIG.fetch("EXTOUT")}/include"
+ end
+
+ 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\n" +
- "create_makefile(#{ext.inspect})\n")
+ $extout = nil
+ if RbConfig::CONFIG.key?("buildlibdir") # The top directory where the libruby is built.
+ # Prepend the dummy macro to bypass the conversion in `with_destdir` on DOSISH
+ # platforms, where the drive letter is replaced with `$(DESTDIR)`. `DESTDIR` is
+ # overridden by the command line argument bellow.
+ RbConfig::MAKEFILE_CONFIG["buildlibdir"] = "$(empty)" + RbConfig::CONFIG["buildlibdir"]
+ end
+ append_cflags '-Wno-declaration-after-statement'
+ #{"append_cflags #{ruby_repository_extra_include_dir.inspect}" if ruby_repository_extra_include_dir}
+ create_makefile(#{ext.inspect})
+ RUBY
output = ruby_exe("extconf.rb")
raise "extconf failed:\n#{output}" unless $?.success?
$stderr.puts output if debug
@@ -64,7 +106,7 @@ def compile_extension(name)
# Do not capture stderr as we want to show compiler warnings
make, opts = setup_make
- output = IO.popen([make, "V=1", "DESTDIR=", opts], &:read)
+ output = IO.popen([*make, "V=1", "DESTDIR=", opts], &:read)
raise "#{make} failed:\n#{output}" unless $?.success?
$stderr.puts output if debug
@@ -81,32 +123,42 @@ end
def setup_make
make = ENV['MAKE']
make ||= (RbConfig::CONFIG['host_os'].include?("mswin") ? "nmake" : "make")
- make_flags = ENV["MAKEFLAGS"] || ''
+ env = %w[MFLAGS MAKEFLAGS GNUMAKEFLAGS].to_h {|var| [var, ENV[var]]}
+ 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}"
+ 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
+ [$1, $2].each do |fd|
+ fd = IO.for_fd(fd.to_i(10), autoclose: false)
+ opts[fd] = fd
+ rescue
+ # Jobserver is not usable, maybe no `+` flag or on Windows.
+ job_options = /\A\s*(?:-j\d+\s*|-\S+\Kj\d+)|(?:\G|\s)\K--jobserver-(?:auth|fds)=\S+\s*/
+ env["MAKEFLAGS"] = make_flags.gsub(job_options, '')
+ %w[GNUMAKEFLAGS MFLAGS].each do |var|
+ if flags = env[var]
+ env[var] = flags.gsub(job_options, '')
+ end
+ end
+ opts.clear
+ break
end
end
- [make, opts]
+ [[env, make], opts]
end
def load_extension(name)
- require compile_extension(name)
-rescue LoadError
- if %r{/usr/sbin/execerror ruby "\(ld 3 1 main ([/a-zA-Z0-9_\-.]+_spec\.so)"} =~ $!.message
+ 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
@@ -114,3 +166,7 @@ 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'