diff options
Diffstat (limited to 'lib/rubygems/ext')
-rw-r--r-- | lib/rubygems/ext/build_error.rb | 3 | ||||
-rw-r--r-- | lib/rubygems/ext/builder.rb | 82 | ||||
-rw-r--r-- | lib/rubygems/ext/cargo_builder.rb | 270 | ||||
-rw-r--r-- | lib/rubygems/ext/cargo_builder/link_flag_converter.rb | 14 | ||||
-rw-r--r-- | lib/rubygems/ext/cmake_builder.rb | 4 | ||||
-rw-r--r-- | lib/rubygems/ext/configure_builder.rb | 3 | ||||
-rw-r--r-- | lib/rubygems/ext/ext_conf_builder.rb | 25 | ||||
-rw-r--r-- | lib/rubygems/ext/rake_builder.rb | 14 |
8 files changed, 241 insertions, 174 deletions
diff --git a/lib/rubygems/ext/build_error.rb b/lib/rubygems/ext/build_error.rb index 8ef57ed91a..0329c1eec3 100644 --- a/lib/rubygems/ext/build_error.rb +++ b/lib/rubygems/ext/build_error.rb @@ -1,8 +1,9 @@ # frozen_string_literal: true + ## # Raised when there is an error while building extensions. -require_relative '../exceptions' +require_relative "../exceptions" class Gem::Ext::BuildError < Gem::InstallError end diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 99dd2c162c..be1ba3031c 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -1,11 +1,13 @@ # frozen_string_literal: true + #-- # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. # All rights reserved. # See LICENSE.txt for permissions. #++ -require_relative '../user_interaction' +require_relative "../user_interaction" +require_relative "../shellwords" class Gem::Ext::Builder include Gem::UserInteraction @@ -17,30 +19,28 @@ class Gem::Ext::Builder $1.downcase end - def self.make(dest_path, results, make_dir = Dir.pwd, sitedir = nil) - unless File.exist? File.join(make_dir, 'Makefile') - raise Gem::InstallError, 'Makefile not found' + def self.make(dest_path, results, make_dir = Dir.pwd, sitedir = nil, targets = ["clean", "", "install"]) + unless File.exist? File.join(make_dir, "Makefile") + raise Gem::InstallError, "Makefile not found" end # try to find make program from Ruby configure arguments first - RbConfig::CONFIG['configure_args'] =~ /with-make-prog\=(\w+)/ - make_program_name = ENV['MAKE'] || ENV['make'] || $1 - unless make_program_name - make_program_name = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make' - end + RbConfig::CONFIG["configure_args"] =~ /with-make-prog\=(\w+)/ + make_program_name = ENV["MAKE"] || ENV["make"] || $1 + make_program_name ||= RUBY_PLATFORM.include?("mswin") ? "nmake" : "make" make_program = Shellwords.split(make_program_name) # The installation of the bundled gems is failed when DESTDIR is empty in mswin platform. - destdir = (/\bnmake/i !~ make_program_name || ENV['DESTDIR'] && ENV['DESTDIR'] != "") ? 'DESTDIR=%s' % ENV['DESTDIR'] : '' + destdir = /\bnmake/i !~ make_program_name || ENV["DESTDIR"] && ENV["DESTDIR"] != "" ? format("DESTDIR=%s", ENV["DESTDIR"]) : "" env = [destdir] if sitedir - env << 'sitearchdir=%s' % sitedir - env << 'sitelibdir=%s' % sitedir + env << format("sitearchdir=%s", sitedir) + env << format("sitelibdir=%s", sitedir) end - ['clean', '', 'install'].each do |target| + targets.each do |target| # Pass DESTDIR via command line to override what's in MAKEFLAGS cmd = [ *make_program, @@ -50,39 +50,62 @@ class Gem::Ext::Builder begin run(cmd, results, "make #{target}".rstrip, make_dir) rescue Gem::InstallError - raise unless target == 'clean' # ignore clean failure + raise unless target == "clean" # ignore clean failure end end end + def self.ruby + # Gem.ruby is quoted if it contains whitespace + cmd = Shellwords.split(Gem.ruby) + + # This load_path is only needed when running rubygems test without a proper installation. + # Prepending it in a normal installation will cause problem with order of $LOAD_PATH. + # Therefore only add load_path if it is not present in the default $LOAD_PATH. + load_path = File.expand_path("../..", __dir__) + case load_path + when RbConfig::CONFIG["sitelibdir"], RbConfig::CONFIG["vendorlibdir"], RbConfig::CONFIG["rubylibdir"] + cmd + else + cmd << "-I#{load_path}" + end + end + def self.run(command, results, command_name = nil, dir = Dir.pwd, env = {}) verbose = Gem.configuration.really_verbose begin - rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], nil + rubygems_gemdeps = ENV["RUBYGEMS_GEMDEPS"] + ENV["RUBYGEMS_GEMDEPS"] = nil if verbose puts("current directory: #{dir}") p(command) end results << "current directory: #{dir}" - require "shellwords" - results << command.shelljoin + results << Shellwords.join(command) require "open3" # Set $SOURCE_DATE_EPOCH for the subprocess. - build_env = { 'SOURCE_DATE_EPOCH' => Gem.source_date_epoch_string }.merge(env) + build_env = { "SOURCE_DATE_EPOCH" => Gem.source_date_epoch_string }.merge(env) output, status = begin - Open3.capture2e(build_env, *command, :chdir => dir) - rescue => error + Open3.popen2e(build_env, *command, chdir: dir) do |_stdin, stdouterr, wait_thread| + output = String.new + while line = stdouterr.gets + output << line + if verbose + print line + end + end + [output, wait_thread.value] + end + rescue StandardError => error raise Gem::InstallError, "#{command_name || class_name} failed#{error.message}" end - if verbose - puts output - else + unless verbose results << output end ensure - ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps + ENV["RUBYGEMS_GEMDEPS"] = rubygems_gemdeps end unless status.success? @@ -131,8 +154,7 @@ class Gem::Ext::Builder when /CMakeLists.txt/ then Gem::Ext::CmakeBuilder when /Cargo.toml/ then - # We use the spec name here to ensure we invoke the correct init function later - Gem::Ext::CargoBuilder.new(@spec) + Gem::Ext::CargoBuilder.new else build_error("No builder for extension '#{extension}'") end @@ -174,7 +196,7 @@ EOF verbose { results.join("\n") } write_gem_make_out results.join "\n" - rescue => e + rescue StandardError => e results << e.message build_error(results.join("\n"), $@) end @@ -190,7 +212,7 @@ EOF if @build_args.empty? say "Building native extensions. This could take a while..." else - say "Building native extensions with: '#{@build_args.join ' '}'" + say "Building native extensions with: '#{@build_args.join " "}'" say "This could take a while..." end @@ -212,11 +234,11 @@ EOF # Writes +output+ to gem_make.out in the extension install directory. def write_gem_make_out(output) # :nodoc: - destination = File.join @spec.extension_dir, 'gem_make.out' + destination = File.join @spec.extension_dir, "gem_make.out" FileUtils.mkdir_p @spec.extension_dir - File.open destination, 'wb' do |io| + File.open destination, "wb" do |io| io.puts output end diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb index 232c0a313d..86a0e73f28 100644 --- a/lib/rubygems/ext/cargo_builder.rb +++ b/lib/rubygems/ext/cargo_builder.rb @@ -1,80 +1,131 @@ # frozen_string_literal: true +require_relative "../shellwords" + # This class is used by rubygems to build Rust extensions. It is a thin-wrapper # over the `cargo rustc` command which takes care of building Rust code in a way # that Ruby can use. class Gem::Ext::CargoBuilder < Gem::Ext::Builder attr_accessor :spec, :runner, :profile - def initialize(spec) + def initialize require_relative "../command" require_relative "cargo_builder/link_flag_converter" - @spec = spec @runner = self.class.method(:run) @profile = :release end - def build(_extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd) + def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd) + require "tempfile" require "fileutils" - require "shellwords" - build_crate(dest_path, results, args, cargo_dir) - validate_cargo_build!(dest_path) - rename_cdylib_for_ruby_compatibility(dest_path) - finalize_directory(dest_path, lib_dir, cargo_dir) - results - end + # Where's the Cargo.toml of the crate we're building + cargo_toml = File.join(cargo_dir, "Cargo.toml") + # What's the crate's name + crate_name = cargo_crate_name(cargo_dir, cargo_toml, results) + + begin + # Create a tmp dir to do the build in + tmp_dest = Dir.mktmpdir(".gem.", cargo_dir) + + # Run the build + cmd = cargo_command(cargo_toml, tmp_dest, args, crate_name) + runner.call(cmd, results, "cargo", cargo_dir, build_env) + + # Where do we expect Cargo to write the compiled library + dylib_path = cargo_dylib_path(tmp_dest, crate_name) + + # Helpful error if we didn't find the compiled library + raise DylibNotFoundError, tmp_dest unless File.exist?(dylib_path) - def build_crate(dest_path, results, args, cargo_dir) - env = build_env - cmd = cargo_command(cargo_dir, dest_path, args) - runner.call cmd, results, 'cargo', cargo_dir, env + # Cargo and Ruby differ on how the library should be named, rename from + # what Cargo outputs to what Ruby expects + dlext_name = "#{crate_name}.#{makefile_config("DLEXT")}" + dlext_path = File.join(File.dirname(dylib_path), dlext_name) + FileUtils.cp(dylib_path, dlext_path) + + nesting = extension_nesting(extension) + + if Gem.install_extension_in_lib && lib_dir + nested_lib_dir = File.join(lib_dir, nesting) + FileUtils.mkdir_p nested_lib_dir + FileUtils.cp_r dlext_path, nested_lib_dir, remove_destination: true + end + + # move to final destination + nested_dest_path = File.join(dest_path, nesting) + FileUtils.mkdir_p nested_dest_path + FileUtils.cp_r dlext_path, nested_dest_path, remove_destination: true + ensure + # clean up intermediary build artifacts + FileUtils.rm_rf tmp_dest if tmp_dest + end results end def build_env build_env = rb_config_env - build_env["RUBY_STATIC"] = "true" if ruby_static? && ENV.key?('RUBY_STATIC') + build_env["RUBY_STATIC"] = "true" if ruby_static? && ENV.key?("RUBY_STATIC") + cfg = "--cfg=rb_sys_gem --cfg=rubygems --cfg=rubygems_#{Gem::VERSION.tr(".", "_")}" + build_env["RUSTFLAGS"] = [ENV["RUSTFLAGS"], cfg].compact.join(" ") build_env end - def cargo_command(cargo_dir, dest_path, args = []) - manifest = File.join(cargo_dir, "Cargo.toml") - cargo = ENV.fetch("CARGO", "cargo") - + def cargo_command(cargo_toml, dest_path, args = [], crate_name = nil) cmd = [] cmd += [cargo, "rustc"] - cmd += ["--target", ENV['CARGO_BUILD_TARGET']] if ENV['CARGO_BUILD_TARGET'] + cmd += ["--crate-type", "cdylib"] + cmd += ["--target", ENV["CARGO_BUILD_TARGET"]] if ENV["CARGO_BUILD_TARGET"] cmd += ["--target-dir", dest_path] - cmd += ["--manifest-path", manifest] + cmd += ["--manifest-path", cargo_toml] cmd += ["--lib"] cmd += ["--profile", profile.to_s] - cmd += ["--locked"] if profile == :release + cmd += ["--locked"] cmd += Gem::Command.build_args cmd += args cmd += ["--"] - cmd += [*cargo_rustc_args(dest_path)] + cmd += [*cargo_rustc_args(dest_path, crate_name)] cmd end private + def cargo + ENV.fetch("CARGO", "cargo") + end + + # returns the directory nesting of the extension, ignoring the first part, so + # "ext/foo/bar/Cargo.toml" becomes "foo/bar" + def extension_nesting(extension) + parts = extension.to_s.split(Regexp.union([File::SEPARATOR, File::ALT_SEPARATOR].compact)) + + parts = parts.each_with_object([]) do |segment, final| + next if segment == "." + if segment == ".." + raise Gem::InstallError, "extension outside of gem root" if final.empty? + next final.pop + end + final << segment + end + + File.join(parts[1...-1]) + end + def rb_config_env result = {} RbConfig::CONFIG.each {|k, v| result["RBCONFIG_#{k}"] = v } result end - def cargo_rustc_args(dest_dir) + def cargo_rustc_args(dest_dir, crate_name) [ *linker_args, *mkmf_libpath, - *rustc_dynamic_linker_flags(dest_dir), + *rustc_dynamic_linker_flags(dest_dir, crate_name), *rustc_lib_flags(dest_dir), *platform_specific_rustc_args(dest_dir), - *debug_flags, ] end @@ -92,6 +143,9 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder # run on one that isn't the missing libraries will cause the extension # to fail on start. flags += ["-C", "link-arg=-static-libgcc"] + elsif darwin_target? + # Ventura does not always have this flag enabled + flags += ["-C", "link-arg=-Wl,-undefined,dynamic_lookup"] end flags @@ -100,14 +154,23 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder # We want to use the same linker that Ruby uses, so that the linker flags from # mkmf work properly. def linker_args - # Have to handle CC="cl /nologo" on mswin cc_flag = Shellwords.split(makefile_config("CC")) linker = cc_flag.shift link_args = cc_flag.flat_map {|a| ["-C", "link-arg=#{a}"] } + return mswin_link_args if linker == "cl" + ["-C", "linker=#{linker}", *link_args] end + def mswin_link_args + args = [] + args += ["-l", makefile_config("LIBRUBYARG_SHARED").chomp(".lib")] + args += split_flags("LIBS").flat_map {|lib| ["-l", lib.chomp(".lib")] } + args += split_flags("LOCAL_LIBS").flat_map {|lib| ["-l", lib.chomp(".lib")] } + args + end + def libruby_args(dest_dir) libs = makefile_config(ruby_static? ? "LIBRUBYARG_STATIC" : "LIBRUBYARG_SHARED") raw_libs = Shellwords.split(libs) @@ -120,44 +183,72 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder makefile_config("ENABLE_SHARED") == "no" end - # Ruby expects the dylib to follow a file name convention for loading - def rename_cdylib_for_ruby_compatibility(dest_path) - new_path = final_extension_path(dest_path) - FileUtils.cp(cargo_dylib_path(dest_path), new_path) - new_path + def cargo_dylib_path(dest_path, crate_name) + prefix = so_ext == "dll" ? "" : "lib" + path_parts = [dest_path] + path_parts << ENV["CARGO_BUILD_TARGET"] if ENV["CARGO_BUILD_TARGET"] + path_parts += ["release", "#{prefix}#{crate_name}.#{so_ext}"] + File.join(*path_parts) end - def validate_cargo_build!(dir) - dylib_path = cargo_dylib_path(dir) + def cargo_crate_name(cargo_dir, manifest_path, results) + require "open3" + Gem.load_yaml - raise DylibNotFoundError, dir unless File.exist?(dylib_path) + output, status = + begin + Open3.capture2e(cargo, "metadata", "--no-deps", "--format-version", "1", chdir: cargo_dir) + rescue StandardError => error + raise Gem::InstallError, "cargo metadata failed #{error.message}" + end - dylib_path - end + unless status.success? + if Gem.configuration.really_verbose + puts output + else + results << output + end - def final_extension_path(dest_path) - dylib_path = cargo_dylib_path(dest_path) - dlext_name = "#{spec.name}.#{makefile_config("DLEXT")}" - dylib_path.gsub(File.basename(dylib_path), dlext_name) - end + exit_reason = + if status.exited? + ", exit code #{status.exitstatus}" + elsif status.signaled? + ", uncaught signal #{status.termsig}" + end - def cargo_dylib_path(dest_path) - prefix = so_ext == "dll" ? "" : "lib" - path_parts = [dest_path] - path_parts << ENV['CARGO_BUILD_TARGET'] if ENV['CARGO_BUILD_TARGET'] - path_parts += [profile_target_directory, "#{prefix}#{cargo_crate_name}.#{so_ext}"] - File.join(*path_parts) + raise Gem::InstallError, "cargo metadata failed#{exit_reason}" + end + + # cargo metadata output is specified as json, but with the + # --format-version 1 option the output is compatible with YAML, so we can + # avoid the json dependency + metadata = Gem::SafeYAML.safe_load(output) + package = metadata["packages"].find {|pkg| normalize_path(pkg["manifest_path"]) == manifest_path } + unless package + found = metadata["packages"].map {|md| "#{md["name"]} at #{md["manifest_path"]}" } + raise Gem::InstallError, <<-EOF +failed to determine cargo package name + +looking for: #{manifest_path} + +found: +#{found.join("\n")} +EOF + end + package["name"].tr("-", "_") end - def cargo_crate_name - spec.metadata.fetch('cargo_crate_name', spec.name).tr('-', '_') + def normalize_path(path) + return path unless File::ALT_SEPARATOR + + path.tr(File::ALT_SEPARATOR, File::SEPARATOR) end - def rustc_dynamic_linker_flags(dest_dir) - split_flags("DLDFLAGS") - .map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir) } - .compact - .flat_map {|arg| ldflag_to_link_modifier(arg) } + def rustc_dynamic_linker_flags(dest_dir, crate_name) + split_flags("DLDFLAGS"). + map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir, crate_name) }. + compact. + flat_map {|arg| ldflag_to_link_modifier(arg) } end def rustc_lib_flags(dest_dir) @@ -189,8 +280,8 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder !!Gem::WIN_PATTERNS.find {|r| target_platform =~ r } end - # Interpolate substition vars in the arg (i.e. $(DEFFILE)) - def maybe_resolve_ldflag_variable(input_arg, dest_dir) + # Interpolate substitution vars in the arg (i.e. $(DEFFILE)) + def maybe_resolve_ldflag_variable(input_arg, dest_dir, crate_name) var_matches = input_arg.match(/\$\((\w+)\)/) return input_arg unless var_matches @@ -201,27 +292,27 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder case var_name # On windows, it is assumed that mkmf has setup an exports file for the - # extension, so we have to to create one ourselves. + # extension, so we have to create one ourselves. when "DEFFILE" - write_deffile(dest_dir) + write_deffile(dest_dir, crate_name) else RbConfig::CONFIG[var_name] end end - def write_deffile(dest_dir) - deffile_path = File.join(dest_dir, "#{spec.name}-#{RbConfig::CONFIG["arch"]}.def") + def write_deffile(dest_dir, crate_name) + deffile_path = File.join(dest_dir, "#{crate_name}-#{RbConfig::CONFIG["arch"]}.def") export_prefix = makefile_config("EXPORT_PREFIX") || "" File.open(deffile_path, "w") do |f| f.puts "EXPORTS" - f.puts "#{export_prefix.strip}Init_#{spec.name}" + f.puts "#{export_prefix.strip}Init_#{crate_name}" end deffile_path end - # We have to basically reimplement RbConfig::CONFIG['SOEXT'] here to support + # We have to basically reimplement <code>RbConfig::CONFIG['SOEXT']</code> here to support # Ruby < 2.5 # # @see https://github.com/ruby/ruby/blob/c87c027f18c005460746a74c07cd80ee355b16e4/configure.ac#L3185 @@ -250,59 +341,6 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder RbConfig.expand(val.dup) end - # Good balance between binary size and debugability - def debug_flags - return [] if profile == :dev - - ["-C", "debuginfo=1"] - end - - # Copied from ExtConfBuilder - def finalize_directory(dest_path, lib_dir, extension_dir) - require "fileutils" - require "tempfile" - - ext_path = final_extension_path(dest_path) - - begin - tmp_dest = Dir.mktmpdir(".gem.", extension_dir) - - # Some versions of `mktmpdir` return absolute paths, which will break make - # if the paths contain spaces. - # - # As such, we convert to a relative path. - tmp_dest_relative = get_relative_path(tmp_dest.clone, extension_dir) - - full_tmp_dest = File.join(extension_dir, tmp_dest_relative) - - # TODO: remove in RubyGems 4 - if Gem.install_extension_in_lib && lib_dir - FileUtils.mkdir_p lib_dir - FileUtils.cp_r ext_path, lib_dir, remove_destination: true - end - - FileUtils::Entry_.new(full_tmp_dest).traverse do |ent| - destent = ent.class.new(dest_path, ent.rel) - destent.exist? || FileUtils.mv(ent.path, destent.path) - end - ensure - FileUtils.rm_rf tmp_dest if tmp_dest - end - end - - def get_relative_path(path, base) - path[0..base.length - 1] = "." if path.start_with?(base) - path - end - - def profile_target_directory - case profile - when :release then 'release' - when :dev then 'debug' - else raise "unknown target directory for profile: #{profile}" - end - end - # Error raised when no cdylib artifact was created class DylibNotFoundError < StandardError def initialize(dir) diff --git a/lib/rubygems/ext/cargo_builder/link_flag_converter.rb b/lib/rubygems/ext/cargo_builder/link_flag_converter.rb index 111bb05492..e4d196cb10 100644 --- a/lib/rubygems/ext/cargo_builder/link_flag_converter.rb +++ b/lib/rubygems/ext/cargo_builder/link_flag_converter.rb @@ -3,20 +3,24 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder # Converts Ruby link flags into something cargo understands class LinkFlagConverter + FILTERED_PATTERNS = [ + /compress-debug-sections/, # Not supported by all linkers, and not required for Rust + ].freeze + def self.convert(arg) + return [] if FILTERED_PATTERNS.any? {|p| p.match?(arg) } + case arg.chomp when /^-L\s*(.+)$/ ["-L", "native=#{$1}"] when /^--library=(\w+\S+)$/, /^-l\s*(\w+\S+)$/ ["-l", $1] - when /^-l\s*:lib(\S+).a$/ - ["-l", "static=#{$1}"] - when /^-l\s*:lib(\S+).(so|dylib|dll)$/ - ["-l", "dylib=#{$1}"] + when /^-l\s*([^:\s])+/ # -lfoo, but not -l:libfoo.a + ["-l", $1] when /^-F\s*(.*)$/ ["-l", "framework=#{$1}"] else - ["-C", "link_arg=#{arg}"] + ["-C", "link-args=#{arg}"] end end end diff --git a/lib/rubygems/ext/cmake_builder.rb b/lib/rubygems/ext/cmake_builder.rb index e47cabef84..b162664784 100644 --- a/lib/rubygems/ext/cmake_builder.rb +++ b/lib/rubygems/ext/cmake_builder.rb @@ -2,8 +2,8 @@ class Gem::Ext::CmakeBuilder < Gem::Ext::Builder def self.build(extension, dest_path, results, args=[], lib_dir=nil, cmake_dir=Dir.pwd) - unless File.exist?(File.join(cmake_dir, 'Makefile')) - require_relative '../command' + unless File.exist?(File.join(cmake_dir, "Makefile")) + require_relative "../command" cmd = ["cmake", ".", "-DCMAKE_INSTALL_PREFIX=#{dest_path}", *Gem::Command.build_args] run cmd, results, class_name, cmake_dir diff --git a/lib/rubygems/ext/configure_builder.rb b/lib/rubygems/ext/configure_builder.rb index eb2f9fce61..6b8590ba2e 100644 --- a/lib/rubygems/ext/configure_builder.rb +++ b/lib/rubygems/ext/configure_builder.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + #-- # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. # All rights reserved. @@ -7,7 +8,7 @@ class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder def self.build(extension, dest_path, results, args=[], lib_dir=nil, configure_dir=Dir.pwd) - unless File.exist?(File.join(configure_dir, 'Makefile')) + unless File.exist?(File.join(configure_dir, "Makefile")) cmd = ["sh", "./configure", "--prefix=#{dest_path}", *args] run cmd, results, class_name, configure_dir diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb index 2f0183fe2f..fb68a7a8cc 100644 --- a/lib/rubygems/ext/ext_conf_builder.rb +++ b/lib/rubygems/ext/ext_conf_builder.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + #-- # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. # All rights reserved. @@ -7,8 +8,8 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd) - require 'fileutils' - require 'tempfile' + require "fileutils" + require "tempfile" tmp_dest = Dir.mktmpdir(".gem.", extension_dir) @@ -21,17 +22,16 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder destdir = ENV["DESTDIR"] begin - require "shellwords" - cmd = Gem.ruby.shellsplit << "-I" << File.expand_path('../..', __dir__) << File.basename(extension) + cmd = ruby << File.basename(extension) cmd.push(*args) run(cmd, results, class_name, extension_dir) do |s, r| - mkmf_log = File.join(extension_dir, 'mkmf.log') + mkmf_log = File.join(extension_dir, "mkmf.log") if File.exist? mkmf_log unless s.success? r << "To see why this extension failed to compile, please check" \ " the mkmf.log which can be found here:\n" - r << " " + File.join(dest_path, 'mkmf.log') + "\n" + r << " " + File.join(dest_path, "mkmf.log") + "\n" end FileUtils.mv mkmf_log, dest_path end @@ -43,18 +43,19 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder full_tmp_dest = File.join(extension_dir, tmp_dest_relative) - # TODO remove in RubyGems 4 - if Gem.install_extension_in_lib and lib_dir + if Gem.install_extension_in_lib && lib_dir FileUtils.mkdir_p lib_dir entries = Dir.entries(full_tmp_dest) - %w[. ..] entries = entries.map {|entry| File.join full_tmp_dest, entry } - FileUtils.cp_r entries, lib_dir, :remove_destination => true + FileUtils.cp_r entries, lib_dir, remove_destination: true end FileUtils::Entry_.new(full_tmp_dest).traverse do |ent| destent = ent.class.new(dest_path, ent.rel) - destent.exist? or FileUtils.mv(ent.path, destent.path) + destent.exist? || FileUtils.mv(ent.path, destent.path) end + + make dest_path, results, extension_dir, tmp_dest_relative, ["clean"] ensure ENV["DESTDIR"] = destdir end @@ -64,10 +65,8 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder FileUtils.rm_rf tmp_dest if tmp_dest end - private - def self.get_relative_path(path, base) - path[0..base.length - 1] = '.' if path.start_with?(base) + path[0..base.length - 1] = "." if path.start_with?(base) path end end diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb index fed98e741c..0171807b39 100644 --- a/lib/rubygems/ext/rake_builder.rb +++ b/lib/rubygems/ext/rake_builder.rb @@ -1,4 +1,7 @@ # frozen_string_literal: true + +require_relative "../shellwords" + #-- # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. # All rights reserved. @@ -7,20 +10,19 @@ class Gem::Ext::RakeBuilder < Gem::Ext::Builder def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd) - if File.basename(extension) =~ /mkrf_conf/i + if /mkrf_conf/i.match?(File.basename(extension)) run([Gem.ruby, File.basename(extension), *args], results, class_name, extension_dir) end - rake = ENV['rake'] + rake = ENV["rake"] if rake - require "shellwords" - rake = rake.shellsplit + rake = Shellwords.split(rake) else begin - rake = [Gem.ruby, "-I#{File.expand_path("../..", __dir__)}", "-rrubygems", Gem.bin_path('rake', 'rake')] + rake = ruby << "-rrubygems" << Gem.bin_path("rake", "rake") rescue Gem::Exception - rake = [Gem.default_exec_format % 'rake'] + rake = [Gem.default_exec_format % "rake"] end end |