Describe the bug
On Amazon Linux 2023, ruby4.0's RubyGems reports the RPM-provided default gems bigdecimal, io-console, and psych as having unbuilt extensions, even though their .so files and gem.build_complete markers are present. require "bigdecimal" then fails with LoadError outside Bundler.
Gem.default_ext_dir_for("/usr/share/gems/ruby4.0") returns /usr/share/ruby4.0/lib64/gems/ruby/ruby, which does not exist. The distro operating_system.rb derives that path by matching a directory component equal to RUBY_INSTALL_NAME ("ruby"), but the install directories are named ruby4.0, so the match fails and the prefix is wrong.
To Reproduce
Reproducible in a fresh amazonlinux:2023 container:
$ dnf install -y ruby4.0 ruby4.0-rubygems ruby4.0-rubygem-bigdecimal \
ruby4.0-rubygem-psych ruby4.0-rubygem-io-console
$ rpm -q ruby4.0 ruby4.0-rubygems
ruby4.0-4.0.1-32.amzn2023.0.2.aarch64
ruby4.0-rubygems-4.0.3-32.amzn2023.0.2.noarch
$ ruby -e 'require "bigdecimal"'
Ignoring bigdecimal-4.0.1 because its extensions are not built. Try: gem pristine bigdecimal --version 4.0.1
Ignoring io-console-0.8.2 because its extensions are not built. Try: gem pristine io-console --version 0.8.2
Ignoring psych-5.3.1 because its extensions are not built. Try: gem pristine psych --version 5.3.1
Ignoring bigdecimal-4.0.1 because its extensions are not built. Try: gem pristine bigdecimal --version 4.0.1
Ignoring io-console-0.8.2 because its extensions are not built. Try: gem pristine io-console --version 0.8.2
Ignoring psych-5.3.1 because its extensions are not built. Try: gem pristine psych --version 5.3.1
/usr/share/ruby4.0/did_you_mean/core_ext/name_error.rb:11: warning: bigdecimal is not part of the default gems since Ruby 3.4.0. Install bigdecimal from RubyGems.
-e:1:in 'Kernel#require': cannot load such file -- bigdecimal (LoadError)
from -e:1:in '<main>'
# Wrong extension dir vs. the config it is derived from:
$ ruby -e 'require "rbconfig"; puts RbConfig::CONFIG["RUBY_INSTALL_NAME"], RbConfig::CONFIG["vendordir"]'
ruby
/usr/share/ruby4.0/vendor_ruby
$ ruby -e 'require "rubygems"; puts Gem.default_ext_dir_for("/usr/share/gems/ruby4.0")'
/usr/share/ruby4.0/lib64/gems/ruby/ruby
$ ls -d /usr/share/ruby4.0/lib64/gems/ruby/ruby
ls: cannot access '/usr/share/ruby4.0/lib64/gems/ruby/ruby': No such file or directory
# The extensions and markers actually exist here, and the packages are unmodified:
$ find /usr/lib64/gems/ruby4.0 /usr/share/gems/ruby4.0/extensions -name gem.build_complete
/usr/lib64/gems/ruby4.0/json-2.18.0/gem.build_complete
/usr/lib64/gems/ruby4.0/bigdecimal-4.0.1/gem.build_complete
/usr/lib64/gems/ruby4.0/psych-5.3.1/gem.build_complete
/usr/lib64/gems/ruby4.0/io-console-0.8.2/gem.build_complete
/usr/share/gems/ruby4.0/extensions/aarch64-linux/4.0.0/bigdecimal-4.0.1/gem.build_complete
$ rpm -V ruby4.0 ruby4.0-rubygems ruby4.0-rubygem-bigdecimal ruby4.0-rubygem-psych ruby4.0-rubygem-io-console
$ # (no output)
The suggested gem pristine cannot restore these: the RPM packages ship no cached .gem, so it falls back to fetching from rubygems.org and rebuilding, which fails without a Ruby development environment. Note where it writes its build log — the nonexistent extension dir derived above (run this last; it creates that directory and touches files under /usr/share/gems, which perturbs the rpm -V / ls -d checks):
$ gem pristine bigdecimal --version 4.0.1
[...Ignoring warnings as above...]
Restoring gems to pristine condition...
Cached gem for bigdecimal-4.0.1 not found, attempting to fetch...
Building native extensions. This could take a while...
ERROR: While executing gem ... (Gem::Ext::BuildError)
ERROR: Failed to build gem native extension.
current directory: /usr/share/gems/ruby4.0/gems/bigdecimal-4.0.1/ext/bigdecimal
/usr/bin/ruby -I/usr/share/gems/ruby4.0 extconf.rb
[...]
mkmf.rb can't find header files for ruby at /usr/share/include/ruby.h
[...]
Results logged to /usr/share/ruby4.0/lib64/gems/ruby/ruby/bigdecimal-4.0.1/gem_make.out
The derivation, from /usr/share/gems/ruby4.0/rubygems/defaults/operating_system.rb (unmodified, owned by ruby4.0-rubygems):
def previous_but_one_dir_to(path, dir)
return unless path
split_path = path.split(File::SEPARATOR)
File.join(split_path.take_while { |one_dir| one_dir !~ /^#{dir}$/ }[0..-2])
end
def default_locations
@default_locations ||= {
:system => previous_but_one_dir_to(RbConfig::CONFIG['vendordir'], RbConfig::CONFIG['RUBY_INSTALL_NAME']),
...
take_while { |d| d !~ /^ruby$/ } on /usr/share/ruby4.0/vendor_ruby never stops at ruby4.0, so it returns /usr/share/ruby4.0 instead of /usr.
Expected behavior
No "extensions are not built" warnings; require "bigdecimal" succeeds; Gem.default_ext_dir_for("/usr/share/gems/ruby4.0") resolves to /usr/lib64/gems/ruby4.0.
Environment
- Amazon Linux 2023, aarch64. Observed on Amazon Linux 2023.12.20260622 and reproduced in the
amazonlinux:2023 container (Amazon Linux 2023.12.20260710).
ruby4.0-4.0.1-32.amzn2023.0.2, ruby4.0-rubygems-4.0.3-32.amzn2023.0.2, RubyGems 4.0.3.
- No fixed package available (
dnf check-update 'ruby4.0*' returns nothing).
Notes
psych and io-console also have symlinks on the arch load path (/usr/lib64/ruby4.0/psych.so, /usr/lib64/ruby4.0/io/console.so → /usr/lib64/gems/ruby4.0/...), so require works for them despite the warning; only bigdecimal fails to load.
- Workaround: under Bundler with the gem installed to a project-local path (
bundle config set --local path vendor/bundle), the functional LoadError is avoided because Bundler builds and loads its own copy (requires gcc, make, ruby4.0-devel); the warnings still print.
Describe the bug
On Amazon Linux 2023,
ruby4.0's RubyGems reports the RPM-provided default gemsbigdecimal,io-console, andpsychas having unbuilt extensions, even though their.sofiles andgem.build_completemarkers are present.require "bigdecimal"then fails withLoadErroroutside Bundler.Gem.default_ext_dir_for("/usr/share/gems/ruby4.0")returns/usr/share/ruby4.0/lib64/gems/ruby/ruby, which does not exist. The distrooperating_system.rbderives that path by matching a directory component equal toRUBY_INSTALL_NAME("ruby"), but the install directories are namedruby4.0, so the match fails and the prefix is wrong.To Reproduce
Reproducible in a fresh
amazonlinux:2023container:The suggested
gem pristinecannot restore these: the RPM packages ship no cached.gem, so it falls back to fetching from rubygems.org and rebuilding, which fails without a Ruby development environment. Note where it writes its build log — the nonexistent extension dir derived above (run this last; it creates that directory and touches files under/usr/share/gems, which perturbs therpm -V/ls -dchecks):The derivation, from
/usr/share/gems/ruby4.0/rubygems/defaults/operating_system.rb(unmodified, owned byruby4.0-rubygems):take_while { |d| d !~ /^ruby$/ }on/usr/share/ruby4.0/vendor_rubynever stops atruby4.0, so it returns/usr/share/ruby4.0instead of/usr.Expected behavior
No "extensions are not built" warnings;
require "bigdecimal"succeeds;Gem.default_ext_dir_for("/usr/share/gems/ruby4.0")resolves to/usr/lib64/gems/ruby4.0.Environment
amazonlinux:2023container (Amazon Linux 2023.12.20260710).ruby4.0-4.0.1-32.amzn2023.0.2,ruby4.0-rubygems-4.0.3-32.amzn2023.0.2, RubyGems 4.0.3.dnf check-update 'ruby4.0*'returns nothing).Notes
psychandio-consolealso have symlinks on the arch load path (/usr/lib64/ruby4.0/psych.so,/usr/lib64/ruby4.0/io/console.so→/usr/lib64/gems/ruby4.0/...), sorequireworks for them despite the warning; onlybigdecimalfails to load.bundle config set --local path vendor/bundle), the functionalLoadErroris avoided because Bundler builds and loads its own copy (requiresgcc,make,ruby4.0-devel); the warnings still print.