From 66740bbe2e7867bbcb2f4e73b5e85277c4a21f9f Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Thu, 15 Dec 2022 21:01:04 +0000 Subject: Add support for RubyGems 3.3.21 or later (#209) Since Rubygems 3.3.21, the Gem::Platform name always contains the library version for gnu platforms. So where the rake-compiler config entries previously were: ```yaml --- rbconfig-x86_64-linux-gnu-2.7.0: "/usr/local/rake-compiler/ruby/x86_64-redhat-linux/ruby-2.7.0/lib/ruby/2.7.0/x86_64-linux-gnu/rbconfig.rb" rbconfig-x86_64-linux-2.7.0: "/usr/local/rake-compiler/ruby/x86_64-redhat-linux/ruby-2.7.0/lib/ruby/2.7.0/x86_64-linux-gnu/rbconfig.rb" ``` with later versions of rubygems, it is only ```yaml --- rbconfig-x86_64-linux-gnu-2.7.0: "/usr/local/rake-compiler/ruby/x86_64-redhat-linux/ruby-2.7.0/lib/ruby/2.7.0/x86_64-linux-gnu/rbconfig.rb" ``` This means that the current way of finding a matching runtime, by doing a string comparison on the config keys, is no longer appropriate. This is causing failing builds downstream in `rake-compiler-dock`. This PR: - extracts a new CompilerConfig class to encapsulate the logic - uses `Gem::Platform#=~` to tell if the gem platform matches the runtime platform --- lib/rake/baseextensiontask.rb | 2 ++ lib/rake/compiler_config.rb | 38 ++++++++++++++++++++++ lib/rake/extensiontask.rb | 12 +++---- spec/lib/rake/compiler_config_spec.rb | 54 ++++++++++++++++++++++++++++++++ spec/lib/rake/extensiontask_spec.rb | 59 ++++++++++++++++++++++------------- 5 files changed, 137 insertions(+), 28 deletions(-) create mode 100644 lib/rake/compiler_config.rb create mode 100644 spec/lib/rake/compiler_config_spec.rb diff --git a/lib/rake/baseextensiontask.rb b/lib/rake/baseextensiontask.rb index cf32147..063a555 100644 --- a/lib/rake/baseextensiontask.rb +++ b/lib/rake/baseextensiontask.rb @@ -5,6 +5,8 @@ require 'rbconfig' require 'pathname' +require_relative "compiler_config" + module Rake class BaseExtensionTask < TaskLib diff --git a/lib/rake/compiler_config.rb b/lib/rake/compiler_config.rb new file mode 100644 index 0000000..e9832dc --- /dev/null +++ b/lib/rake/compiler_config.rb @@ -0,0 +1,38 @@ +module Rake + class CompilerConfig + def initialize(config_path) + require "yaml" + @config = YAML.load_file(config_path) + end + + def find(ruby_version, gem_platform) + gem_platform = Gem::Platform.new(gem_platform) + + @config.each do |config_name, config_location| + # There are two variations we might find in the rake-compiler config.yml + # + # 1. config_name: rbconfig-x86_64-linux-3.0.0 + # runtime_platform_name: x86_64-linux + # runtime_version: 3.0.0 + # + # 2. config_name: rbconfig-x86_64-linux-gnu-3.0.0 + # runtime_platform_name: x86_64-linux-gnu + # runtime_version: 3.0.0 + # + # With rubygems < 3.3.21, both variations will be present (two entries pointing at the same + # installation). + # + # With rubygems >= 3.3.21, only the second variation will be present. + runtime_platform_name = config_name.split("-")[1..-2].join("-") + runtime_version = config_name.split("-").last + runtime_platform = Gem::Platform.new(runtime_platform_name) + + if (ruby_version == runtime_version) && (gem_platform =~ runtime_platform) + return config_location + end + end + + nil + end + end +end diff --git a/lib/rake/extensiontask.rb b/lib/rake/extensiontask.rb index 7c69741..0f48520 100644 --- a/lib/rake/extensiontask.rb +++ b/lib/rake/extensiontask.rb @@ -393,8 +393,11 @@ Java extension should be preferred. return end - require "yaml" - config_file = YAML.load_file(config_path) + rbconfig_file = Rake::CompilerConfig.new(config_path).find(ruby_ver, for_platform) + unless rbconfig_file + warn "no configuration section for specified version of Ruby (rbconfig-#{for_platform}-#{ruby_ver})" + return + end # tmp_path tmp_path = "#{@tmp_dir}/#{for_platform}/#{@name}/#{ruby_ver}" @@ -405,11 +408,6 @@ Java extension should be preferred. # lib_binary_path lib_binary_path = "#{lib_path}/#{File.basename(binary(for_platform))}" - unless rbconfig_file = config_file["rbconfig-#{for_platform}-#{ruby_ver}"] then - warn "no configuration section for specified version of Ruby (rbconfig-#{for_platform}-#{ruby_ver})" - return - end - # mkmf mkmf_file = File.expand_path(File.join(File.dirname(rbconfig_file), '..', 'mkmf.rb')) diff --git a/spec/lib/rake/compiler_config_spec.rb b/spec/lib/rake/compiler_config_spec.rb new file mode 100644 index 0000000..22b1f7f --- /dev/null +++ b/spec/lib/rake/compiler_config_spec.rb @@ -0,0 +1,54 @@ +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') + +require 'rake/extensiontask' +require 'rbconfig' +require 'tempfile' + +describe Rake::CompilerConfig do + def config_file(contents) + Tempfile.new.tap do |tf| + tf.write(contents) + tf.close + end + end + + it "returns the matching config for exact platform match" do + cc = Rake::CompilerConfig.new(config_file(<<~CONFIG)) + --- + rbconfig-x86_64-linux-3.0.0: "/path/to/aaa/rbconfig.rb" + rbconfig-x86_64-darwin-3.1.0: "/path/to/bbb/rbconfig.rb" + rbconfig-x86_64-linux-3.1.0: "/path/to/ccc/rbconfig.rb" + CONFIG + + expect(cc.find("3.0.0", "x86_64-linux")).to eq("/path/to/aaa/rbconfig.rb") + expect(cc.find("3.1.0", "x86_64-darwin")).to eq("/path/to/bbb/rbconfig.rb") + expect(cc.find("3.1.0", "x86_64-linux")).to eq("/path/to/ccc/rbconfig.rb") + + expect(cc.find("2.7.0", "x86_64-linux")).to be_nil + expect(cc.find("3.1.0", "arm64-linux")).to be_nil + end + + it "returns the matching config for inexact platform match" do + cc = Rake::CompilerConfig.new(config_file(<<~CONFIG)) + --- + rbconfig-x86_64-linux-gnu-3.0.0: "/path/to/aaa/rbconfig.rb" + rbconfig-x86_64-linux-musl-3.1.0: "/path/to/bbb/rbconfig.rb" + CONFIG + + expect(cc.find("3.0.0", "x86_64-linux")).to eq("/path/to/aaa/rbconfig.rb") + expect(cc.find("3.1.0", "x86_64-linux")).to eq("/path/to/bbb/rbconfig.rb") + end + + it "does not match the other way around" do + if Gem::Version.new(Gem::VERSION) < Gem::Version.new("3.3.21") + skip "rubygems 3.3.21+ only" + end + + cc = Rake::CompilerConfig.new(config_file(<<~CONFIG)) + --- + rbconfig-x86_64-linux-3.1.0: "/path/to/bbb/rbconfig.rb" + CONFIG + + expect(cc.find("3.1.0", "x86_64-linux-musl")).to be_nil + end +end diff --git a/spec/lib/rake/extensiontask_spec.rb b/spec/lib/rake/extensiontask_spec.rb index a7eb5e3..1c4c9bb 100644 --- a/spec/lib/rake/extensiontask_spec.rb +++ b/spec/lib/rake/extensiontask_spec.rb @@ -381,9 +381,10 @@ describe Rake::ExtensionTask do end it 'should warn if no section of config file defines running version of ruby' do - config = Hash.new - expect(config).to receive(:[]).with("rbconfig-#{@platform}-#{@ruby_ver}").and_return(nil) - allow(YAML).to receive(:load_file).and_return(config) + allow_any_instance_of(Rake::CompilerConfig).to( + receive(:find).with(@ruby_ver, @platform).and_return(nil) + ) + out, err = capture_output do Rake::ExtensionTask.new('extension_one') do |ext| ext.cross_compile = true @@ -403,9 +404,9 @@ describe Rake::ExtensionTask do end it 'should generate additional rake tasks if files are added when cross compiling' do - config = Hash.new - allow(config).to receive(:[]).and_return('/rubies/1.9.1/rbconfig.rb') - allow(YAML).to receive(:load_file).and_return(config) + allow_any_instance_of(Rake::CompilerConfig).to( + receive(:find).and_return("/rubies/1.9.1/rbconfig.rb") + ) # Use a real spec instead of a mock because define_native_tasks dups and # calls methods on Gem::Specification, which is more than mock can do. @@ -433,9 +434,11 @@ describe Rake::ExtensionTask do end it 'should allow usage of RUBY_CC_VERSION to indicate a different version of ruby' do - config = Hash.new - expect(config).to receive(:[]).with("rbconfig-i386-mingw32-1.9.1").and_return('/rubies/1.9.1/rbconfig.rb') - allow(YAML).to receive(:load_file).and_return(config) + allow_any_instance_of(Rake::CompilerConfig).to( + receive(:find) + .with("1.9.1", "i386-mingw32") + .and_return("/rubies/1.9.1/rbconfig.rb") + ) ENV['RUBY_CC_VERSION'] = '1.9.1' Rake::ExtensionTask.new('extension_one') do |ext| @@ -444,10 +447,16 @@ describe Rake::ExtensionTask do end it 'should allow multiple versions be supplied to RUBY_CC_VERSION' do - config = Hash.new - expect(config).to receive(:[]).once.with("rbconfig-i386-mingw32-1.8.6").and_return('/rubies/1.8.6/rbconfig.rb') - expect(config).to receive(:[]).once.with("rbconfig-i386-mingw32-1.9.1").and_return('/rubies/1.9.1/rbconfig.rb') - allow(YAML).to receive(:load_file).and_return(config) + allow_any_instance_of(Rake::CompilerConfig).to( + receive(:find) + .with("1.8.6", "i386-mingw32") + .and_return("/rubies/1.8.6/rbconfig.rb") + ) + allow_any_instance_of(Rake::CompilerConfig).to( + receive(:find) + .with("1.9.1", "i386-mingw32") + .and_return("/rubies/1.9.1/rbconfig.rb") + ) ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1' Rake::ExtensionTask.new('extension_one') do |ext| @@ -459,18 +468,19 @@ describe Rake::ExtensionTask do platforms = ["x86-mingw32", "x64-mingw32"] ruby_cc_versions = ["1.8.6", "2.1.10", "2.2.6", "2.3.3", "2.10.1", "2.11.0"] ENV["RUBY_CC_VERSION"] = ruby_cc_versions.join(":") - config = Hash.new + ruby_cc_versions.each do |ruby_cc_version| platforms.each do |platform| unless platform == "x64-mingw32" && ruby_cc_version == "2.11.0" rbconf = "/rubies/#{ruby_cc_version}/rbconfig.rb" end - allow(config).to receive(:[]). - with("rbconfig-#{platform}-#{ruby_cc_version}"). - and_return(rbconf) + allow_any_instance_of(Rake::CompilerConfig).to( + receive(:find) + .with(ruby_cc_version, platform) + .and_return(rbconf) + ) end end - allow(YAML).to receive(:load_file).and_return(config) allow(Gem).to receive_message_chain(:configuration, :verbose=).and_return(true) @@ -515,9 +525,16 @@ describe Rake::ExtensionTask do context "(cross compile for multiple versions)" do before :each do - config = Hash.new - allow(config).to receive(:[]).and_return('/rubies/1.8.6/rbconfig.rb', '/rubies/1.9.1/rbconfig.rb') - allow(YAML).to receive(:load_file).and_return(config) + allow_any_instance_of(Rake::CompilerConfig).to( + receive(:find) + .with("1.8.6", "universal-unknown") + .and_return("/rubies/1.8.6/rbconfig.rb") + ) + allow_any_instance_of(Rake::CompilerConfig).to( + receive(:find) + .with("1.9.1", "universal-unknown") + .and_return("/rubies/1.9.1/rbconfig.rb") + ) ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1' @ext = Rake::ExtensionTask.new('extension_one') do |ext| -- cgit v1.2.1