Closed brixen closed 8 years ago
Just an aside relating to the shebang situation, but I look forward to RubyGems #1049 landing.
Standardizing around RUBY_ENGINE_VERSION
seems like a really good idea. In JRuby RUBY_ENGINE_VERSION = JRUBY_VERSION
and in CRuby RUBY_ENGINE_VERSION = RUBY_VERSION
, etc.
The implementation-specific code cannot be removed because that does not solve the problem for existing releases. The implementation specific code could be moved to implementation specific functions.
I also would like to get some shunit2 tests on this behavior. We could download a rbx binary in test/setup
, just like we do with MRI.
I agree that RUBY_ENGINE_VERSION is a useful addition (a perfect counterpart to RUBY_ENGINE) and the patch (sans impl-specific case statement) seems fine to me.
We added this to JRuby: https://github.com/jruby/jruby/issues/2751 . JRuby 1.7.20+ and JRuby 9.0.0.0.pre2+ will have this constant defined.
@postmodern @brixen Do you think we could solve the historical problem and the no-impl-specific code problem by making a new ruby-versions gem which defined RUBY_ENGINE and RUBY_ENGINE_VERSION if they are not defined? Each implementation would probably do a single commit and the gem would never change. All library authors could just depend on the gem. Another gem dep I know, but it seems like a compromise?
Just saw that mruby-1.2.0 also added RUBY_ENGINE_VERSION
, so thinking it's time to come back to this. I will load RUBY_ENGINE_VERSION
if defined but use ${RUBY_ENGINE_VERSION:-$RUBY_VERSION}
in the GEM_HOME
, so that it gracefully falls back to the original behavior for older previously installed rubies with pre-existing gem dirs.
Pushed my own version of this behavior to the ruby_engine_version branch. We'd just need to download a precompiled version of jruby or rubinius and use it to test if RUBY_ENGINE_VERSION
is detected and used within the GEM_HOME
env variable.
CRuby now supports RUBY_ENGINE_VERSION
as well with the release of ruby-2.3.0.
We would need a ruby where RUBY_VERSION != RUBY_ENGINE_VERSION
to properly test the behavior. We could write stub bin/ruby
scripts that mimic the expected behavior. While we wouldn't be testing against the "real deal", stub scripts would allow us to test every edge-case.
The fact that chruby assumes RUBY_VERSION is the correct way to segregate gems on all Ruby implementations causes a great deal of grief for users. Two of the primary problems involve fixed shebangs in gem binary wrappers and conflicting native libraries in C-ext gems.
Sometimes (but not always), rubygems will install a gem binary wrapper with a fixed sheband. For example, the 'bundle' binary wrapper will have a shebang like:
/Users/johnny/.rubies/ruby-2.2.0/bin/ruby
The 'bundle' file itself is in the gem bin directory:
/Users/johnny/.gem/ruby/2.2.0/bin/bundle
Everything works fine until the user installs another Ruby version. Then the user may switch to that version, run
bundle
and the wrong Ruby version will get invoked due to the fixed shebang.For MRI, this is less of an issue, because every release of MRI changes the value of RUBY_VERSION. However, this is not the case for Rubinius nor any other Ruby implementation. Forcing the gem env to use RUBY_VERSION mixes the gem binary wrappers for multiple versions and leads to extremely confusing errors for users. For example, when specifying the ':engine_version' in a Gemfile, the version of Ruby running bundle differs from the version selected with chruby:
$ chruby 2.5 $ ruby -v rubinius 2.5.2 (2.1.0 7a5b05b1 2015-01-30 3.5.1 JI) [x86_64-darwin14.3.0] $ bundle Your rbx version is 2.4.1, but your Gemfile specified rbx 2.5.2
This results because the shebang in the gem wrapper is an absolute path to the 2.4.1 version of Rubinius. Since this directory for the gem binary wrappers is shared across all Rubinius versions, this problem is inevitable.
Very similar to the shebang issue above, this issue involves installing a C-ext gem under a particular version of a Ruby implementation and then loading that gem under another version. For example, Psych uses a C-ext. Installing Psych under one version of Rubinius will build the C-ext against the C-API for that version. When the user installs another version of Rubinius, and then runs
bundle
when Psych is listed as a gem, Bundler will find the installed version and not install a new version. But if the C-API has changed in the new version of Rubinius, the C-ext built against the older version may not load in the newer version. The reverse is also possible: the gem installed under a newer version may not work with an older version.Rubinius added the RUBY_ENGINE constant many years ago to address the challenge of determining which implementation was running the Ruby code. A similar need exists for distinguishing the Ruby engine version, as illustrated above. Rubinius has added the RUBY_ENGINE_VERSION constant and it will be available in 2.5.3+ releases. Just as with RUBY_ENGINE, which was added in MRI 1.9 but never available in MRI <= 1.8.7, we need conditional code to account for RUBY_ENGINE_VERSION not being set. This provides backward compatibility and results in zero behavior change for any existing engines and versions.