From 93ad42814ac56586eb868e139d0a1bcc165ca5fe Mon Sep 17 00:00:00 2001 From: Edouard CHIN Date: Mon, 17 Nov 2025 17:54:03 +0100 Subject: [PATCH] Parse the extconf instead of running it: - Loading the extconf.rb file was required as we need to be able to detect the `create_makefile` call in order to know the resultin binary name (the first argument to the method). We need to know the resulting binary name in order to properly setup rake compiler. Running the extconf was really hacky so instead we'll parse it with Prism. --- Gemfile.lock | 2 + easy_compile.gemspec | 1 + lib/easy_compile/cli.rb | 3 +- lib/easy_compile/compilation_tasks.rb | 47 +++++++--------------- lib/easy_compile/create_makefile_finder.rb | 17 ++++++++ 5 files changed, 36 insertions(+), 34 deletions(-) create mode 100644 lib/easy_compile/create_makefile_finder.rb diff --git a/Gemfile.lock b/Gemfile.lock index c5a848c..a4edcb9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,6 +2,7 @@ PATH remote: . specs: easy_compile (0.1.1) + prism rake-compiler thor @@ -9,6 +10,7 @@ GEM remote: https://rubygems.org/ specs: minitest (5.25.5) + prism (1.6.0) rake (13.3.0) rake-compiler (1.3.0) rake diff --git a/easy_compile.gemspec b/easy_compile.gemspec index 800b57f..4bc5a28 100644 --- a/easy_compile.gemspec +++ b/easy_compile.gemspec @@ -25,4 +25,5 @@ Gem::Specification.new do |spec| spec.add_dependency "rake-compiler" spec.add_dependency "thor" + spec.add_dependency "prism" end diff --git a/lib/easy_compile/cli.rb b/lib/easy_compile/cli.rb index e5dec7b..d68324b 100644 --- a/lib/easy_compile/cli.rb +++ b/lib/easy_compile/cli.rb @@ -134,7 +134,8 @@ def run_rake_tasks!(*tasks) rake_specs = Gem.loaded_specs["rake"] rake_executable = rake_specs.bin_file("rake") rake_path = rake_specs.full_require_paths - load_paths = (rake_compiler_path + rake_path).join(File::PATH_SEPARATOR) + prism_path = Gem.loaded_specs["prism"].full_require_paths + load_paths = (rake_compiler_path + rake_path + prism_path).join(File::PATH_SEPARATOR) system({ "RUBYLIB" => load_paths }, "bundle exec #{RbConfig.ruby} #{rake_executable} #{all_tasks} -R#{rakelibdir}", exception: true) end diff --git a/lib/easy_compile/compilation_tasks.rb b/lib/easy_compile/compilation_tasks.rb index 79be278..ff10471 100644 --- a/lib/easy_compile/compilation_tasks.rb +++ b/lib/easy_compile/compilation_tasks.rb @@ -3,11 +3,11 @@ require "bundler" require "rubygems/package_task" require "rake/extensiontask" +require_relative "create_makefile_finder" module EasyCompile class CompilationTasks attr_reader :gemspec, :native, :create_packaging_task, :extension_task - attr_accessor :binary_name def initialize(create_packaging_task = false, gemspec = nil) @gemspec = Bundler.load_gemspec(gemspec || find_gemspec) @@ -17,10 +17,9 @@ def initialize(create_packaging_task = false, gemspec = nil) end def setup - with_mkmf_monkey_patch do - gemspec.extensions.each do |path| - define_task(path) - end + gemspec.extensions.each do |path| + binary_name = parse_extconf(path) + define_task(path, binary_name) end setup_packaging if create_packaging_task @@ -52,46 +51,21 @@ def setup_packaging end end - def with_mkmf_monkey_patch - require "mkmf" - - instance = self - - previous_create_makefile = method(:create_makefile) - Object.define_method(:create_makefile) do |name, *args| - instance.binary_name = name - previous_create_makefile.call(name, *args) - end - - Object.define_method(:create_rust_makefile) do |name, *args| - instance.binary_name = name - end - - yield - ensure - Object.remove_method(:create_makefile) - Object.remove_method(:create_rust_makefile) - end - - def define_task(path) - require File.expand_path(path) - + def define_task(path, binary_name) @extension_task = Rake::ExtensionTask.new do |ext| ext.name = File.basename(binary_name) ext.config_script = File.basename(path) ext.ext_dir = File.dirname(path) - ext.lib_dir = binary_lib_dir if binary_lib_dir + ext.lib_dir = binary_lib_dir(binary_name) if binary_lib_dir(binary_name) ext.gem_spec = gemspec ext.cross_platform = normalized_platform ext.cross_compile = true end disable_shared unless Gem.win_platform? - ensure - self.binary_name = nil end - def binary_lib_dir + def binary_lib_dir(binary_name) dir = File.dirname(binary_name) return if dir == "." @@ -137,5 +111,12 @@ def verify_gemspec! This tool can't be used on pure Ruby gems. EOM end + + def parse_extconf(path) + visitor = CreateMakefileFinder.new + Prism.parse_file(path).value.accept(visitor) + + visitor.binary_name + end end end diff --git a/lib/easy_compile/create_makefile_finder.rb b/lib/easy_compile/create_makefile_finder.rb new file mode 100644 index 0000000..99bbefd --- /dev/null +++ b/lib/easy_compile/create_makefile_finder.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require "prism" + +module EasyCompile + class CreateMakefileFinder < Prism::Visitor + attr_reader :binary_name + + def visit_call_node(node) + super + looking_for = [:create_makefile, :create_rust_makefile] + return unless looking_for.include?(node.name) + + @binary_name = node.arguments.child_nodes.first.content + end + end +end