Bug #21568
openRequiring core libraries when already requiring multiple user defined libraries with the same name can error
Description
The simplest way to understand this error is that after requiring 2 or more files with the same name as some core libraries, any subsequent calls to require the core library will fail, ie
require '/Users/alex/foo/fiber'
require '/Users/alex/bar/fiber'
require 'fiber'
raises
cannot load such file -- fiber
More detailed instructions to repro this can be found in the code snippet below.
Noting that I am on a Mac, OS 15.6. This is reproducible across my team on a few different OS versions, all Mac. The same underlying issue can also be seen in some other issues like: https://github.com/newrelic/newrelic-ruby-agent/issues/2001
The context this error is discovered in is that some gems may require their own libraries with the same name as core libraries, often wrapping the implementations of those core libraries to extend functionality, like the New Relic ruby agent does with fiber, for example (https://github.com/newrelic/newrelic-ruby-agent/tree/dev/lib/new_relic/agent/instrumentation/fiber).
Then, if 2 or more gems do something like that, and any other gem has require 'fiber'
in it to support old ruby versions where this was necessary, the error occurs.
Full Steps to Reproduce:
# Setup
# =====
# 1. Set this base_dir variable to be an absolute path to a dir
# or something that can be found in your $LOAD_PATH.
base_dir = # ex: "/Users/<you>/ruby_require_test"
# 2. Within that base directory create 2 directories named `foo` and `bar`
# 3. Within both `foo` and `bar` touch new files named
# - complex.rb
# - enumerator.rb
# - fiber.rb
# - rational.rb
# - ruby2_keywords.rb
# - set.rb
# - thread.rb
# Note - this list was generated by running:
# `ruby -ve 'p $LOADED_FEATURES.reject { |feature| %r|/| =~ feature }'`
# which returns: `["enumerator.so", "thread.rb", "fiber.so", "rational.so", "complex.so", "ruby2_keywords.rb"]`
# Reproducing the error:
# After requiring 2 (or more) user defined files with the same name as part of
# the ruby core library that is required as a bare filename, requiring that part of
# the core library will error, ex: `cannot load such file -- fiber`.
# The erroring require statements are all .so files
begin
require "#{base_dir}/foo/complex"
require "#{base_dir}/bar/complex"
require 'complex'
rescue LoadError => e
puts e.message
end
begin
require "#{base_dir}/foo/enumerator"
require "#{base_dir}/bar/enumerator"
require 'enumerator'
rescue LoadError => e
puts e.message
end
begin
require "#{base_dir}/foo/fiber"
require "#{base_dir}/bar/fiber"
require 'fiber'
rescue LoadError => e
puts e.message
end
begin
require "#{base_dir}/foo/rational"
require "#{base_dir}/bar/rational"
require 'rational'
rescue LoadError => e
puts e.message
end
# The following examples do not error.
# The difference seems to be that the core lib files are defined as .rb not .so
begin
require "#{base_dir}/foo/ruby2_keywords"
require "#{base_dir}/bar/ruby2_keywords"
require 'ruby2_keywords'
rescue LoadError => e
puts e.message
end
begin
require "#{base_dir}/foo/set"
require "#{base_dir}/bar/set"
require 'set'
rescue LoadError => e
puts e.message
end
begin
require "#{base_dir}/foo/thread"
require "#{base_dir}/bar/thread"
require 'thread'
rescue LoadError => e
puts e.message
end