Issue #22438 has been reported by mbideau (Michael Bideau). ---------------------------------------- Bug #22438: mkmf.rb do not work with /home mounted with noexec https://bugs.ruby-lang.org/issues/22438 * Author: mbideau (Michael Bideau) * Status: Open * ruby -v: ruby 3.3.8 (2025-04-09 revision b200bad6cd) [x86_64-linux-gnu] * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- When trying to install a *vagrant* plugin (here *vagrant-libvirt*), it uses the file **mkmf.rb** (here `/opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb`) and this fail with the following error message:
Vagrant failed to install the requested plugin because development tools are required for installation but are not currently installed on this machine. Please install development tools and then try this command again.
It is the user facing error message that is from the following underlying command: ``` /opt/vagrant/embedded/bin/ruby --verbose extconf.rb checking for pkg-config for libvirt... /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:480:in `try_do': The compiler failed to generate an executable file. (RuntimeError) You have to install development tools first. from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:573:in `try_link0' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:591:in `try_link' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:683:in `try_ldflags' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:1896:in `block in pkg_config' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:983:in `block in checking_for' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:344:in `block (2 levels) in postpone' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:314:in `open' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:344:in `block in postpone' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:314:in `open' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:340:in `postpone' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:982:in `checking_for' from /opt/vagrant/embedded/lib/ruby/3.3.0/mkmf.rb:1862:in `pkg_config' from extconf.rb:5:in `<main>' ``` The mentioned `try_do` function is where the issue is. Here is its code (as the ruby version 3.3.8): ```ruby def try_do(src, command, *opts, &b) unless have_devel? raise <<MSG The compiler failed to generate an executable file. You have to install development tools first. MSG end begin src = create_tmpsrc(src, &b) xsystem(command, *opts) ensure log_src(src) end end ``` Which is called by `try_link0` function that has the following code: ```ruby def try_link0(src, opt="", *opts, &b) # :nodoc: exe = CONFTEST+$EXEEXT cmd = link_command("", opt) if $universal require 'tmpdir' Dir.mktmpdir("mkmf_", oldtmpdir = ENV["TMPDIR"]) do |tmpdir| begin ENV["TMPDIR"] = tmpdir try_do(src, cmd, *opts, &b) ensure ENV["TMPDIR"] = oldtmpdir end end else try_do(src, cmd, *opts, &b) end and File.executable?(exe) or return nil exe ensure MakeMakefile.rm_rf(*Dir["#{CONFTEST}*"]-[exe]) end ``` So you can see, if my understanding is correct, that the environment variable`TMPDIR`, despite being set, is never used/honored to execute the command. The command is still running in the current working directory, and the `TMPDIR` is ignored/useless. In my case the current working directory is `~/.vagrant.d/gems/3.3.8/gems/ruby-libvirt-0.8.4/ext/libvirt` which is in my */home* mounted with `noexec`. This makes `File.executable?(exe)` (`exe` is the compiled file) returning `false` because the source and the compiled file (even if they are just to test) end up in my working directory and not in the temporary directory specified with the environment variable **TMPDIR** which have `exec` permission. So I suggest to always use a temporary directory to execute all the tests contained in this code file **mkmf.rb** and to actually honor `TMPDIR` when defined. -- https://bugs.ruby-lang.org/