Ruby-build: Introduce --disable-shared flag

Created on 3 Dec 2019  路  7Comments  路  Source: rbenv/ruby-build

Force enabling shared libraries is causing some issues in my environment. Currently, I am locking my environment to the git sha (on ruby-build) before this change was introduced. I am still looking into moving everything over to be compatible with this change, but a flag would be very helpful, especially since there is no obvious way to prevent this this change from happening.

1368

Most helpful comment

Hello,

We ran into this issue as well, for I believe the same reason. Our builds (i.e. bundle installs) may run on different machines than our production runtime machines, and also may be cached for later execution. So we have some previous bundles that were built using Rubies installed prior to Oct 30 (and thus built without --enable-shared), and these are not compatible with newer runtime machines running Rubies that were installed after Oct 30 (and thus use --enable-shared), because C extensions are not compatible between those Rubies.

We are a large cloud provider, and those bundle builds are owned by our customers, so we cannot just go through and rebuild all the existing bundles using --enable-shared. Instead, we need to ensure that a Ruby _without_ --enable-shared is installed on our runtime machines, to maintain compatibility with those existing apps/bundles.

We will implement the workaround of creating a custom build definition for now. However, I did want to add our voice to the desire for an easier way to do this.

All 7 comments

Hi @mrenteria thank you for reporting. Can you share more info about the issues you're having due to --enable-shared, perhaps by pasting specific error messages and gems you might have problems installing? This would help others find this issue too.

In a nutshell, we are compiling assets on one machine and utilizing them on another. Since we are installing rbenv and ruby-build through git and the master branch we hit a point where newly spun up machines were not functioning properly due to issues with built extensions (i.e. nokogiri). This is because the machine that compiled the assets did not build ruby with the enabled-shared flag, and the new machines did build ruby with the enable-shared flag.

We are still doing tests to see if are deploy times are more effective with or without the enabled-shared flag. The bottom line is that it may be of interest to someone to install and build ruby without shared extensions, and I am unable to find any "good" way to do it without an added flag on the ruby-build side.

For others that are reading this, the most obvious change from this flag for me is the change from

vendor/bundle/ruby/2.6.0/extensions/x86_64-linux/2.6.0-static

to

vendor/bundle/ruby/2.6.0/extensions/x86_64-linux/2.6.0

You can find the actual code that creates this distinction in rubygems repo

https://github.com/rubygems/rubygems/blob/b944691ee314cc2a4166152e818b790d9b4c6cf2/lib/rubygems.rb#L472-L482

Thank you for your time @mislav , hopefully this will help someone else.

Thank you for sharing details!

The bottom line is that it may be of interest to someone to install and build ruby without shared extensions, and I am unable to find any "good" way to do it without an added flag on the ruby-build side.

If it's really important for your production environment to not have --enable-shared, I have outlined one potential workaround here. The idea is what if you need to control detailed aspects of a Ruby install, you may want to consider custom build definitions.

Hello,

We ran into this issue as well, for I believe the same reason. Our builds (i.e. bundle installs) may run on different machines than our production runtime machines, and also may be cached for later execution. So we have some previous bundles that were built using Rubies installed prior to Oct 30 (and thus built without --enable-shared), and these are not compatible with newer runtime machines running Rubies that were installed after Oct 30 (and thus use --enable-shared), because C extensions are not compatible between those Rubies.

We are a large cloud provider, and those bundle builds are owned by our customers, so we cannot just go through and rebuild all the existing bundles using --enable-shared. Instead, we need to ensure that a Ruby _without_ --enable-shared is installed on our runtime machines, to maintain compatibility with those existing apps/bundles.

We will implement the workaround of creating a custom build definition for now. However, I did want to add our voice to the desire for an easier way to do this.

Hi there
We have also found another consequence of this change and would appreciate an easy way to turn it off.

We have a number of Rails applications installed across multiple servers, they are deployed with Capistrano, and dependencies are installed with Bundler into separate directories for each application (all standard stuff).

Each application defines a major.minor version of Ruby in .ruby-version file (eg 2.6) and we create a symlink under .rbenv/versions as an 'alias' to point to the actual version of Ruby that's installed on the server (eg ln -sfn $RBENV_DIR/versions/2.6.5 $RBENV_DIR/versions/2.6).

Keeping the teeny version of Ruby up-to-date on the servers with minimal impact on users is important for us. We periodically install the latest version (eg 2.6.6) and then switch the symlink from 2.6.5 to 2.6.6 and restart the apps. We don't expect any compatibility problems doing this!

The change to turn on ENABLE_SHARED by default has broken this for us as Bundler can't find the gems properly any more - under 2.6.5 it's looking in a directory called ruby/2.6.0/extensions/x86_64-linux/2.6.0-static and in the newly installed 2.6.6 it's looking in ruby/2.6.0/extensions/x86_64-linux/2.6.0 which obviously doesn't exist.

I hope that I've explained that clearly and you can understand our problem. I will look at the workaround that you've outlined but would really appreciate a way to revert to the old behaviour.

Many thanks.

:wave: Hello! Another example.

I am running Fedora 32 and Homebrew (Linuxbrew got merged into mainline Homebrew). Through a combination of things, I cannot run ruby-build's provided build definitions which use enabled_shared when the ruby-build's ruby and the installed Homebrew ruby have matching MAJOR.MINOR versions.

I was expecting that RUBY_CONFIGURE_OPTS='--enable-shared=no' would force that option to ./configure, but it looks like the configure opts from the build definitions take precedence. Either a top level ruby-build --disable-shared flag or letting RUBY_CONFIGURE_OPTS take precedence would be a better experience than editing or providing custom ruby-build build definitions.

Here's what is happening:

Homebrew brings in gcc and ruby as Homebrew dependencies for unrelated packages.

Homebrew's gcc has a spec file that forces in -rpath #{HOMEBREW_PREFIX}/lib as linker options. Presuming this is done to get several packages in (Linux)brew to function correctly. https://github.com/Homebrew/linuxbrew-core/blob/master/Formula/gcc.rb#L219-L240

Homebrew's ruby is 2.7.1. It installs #{HOMEBREW_PREFIX}/lib/libruby.so.2.7.

ruby-build, installed either by git checkout or by Homebrew, runs configure with --enable-shared. The built ruby binary has a NEEDED dependency on libruby.so.2.7 and a RPATH of #{HOMEBREW_PREFIX}/lib/libruby.so.2.7:${PREFIX_USED_WITH_RUBY_BUILD}. ldd will show the ruby binary is going to bring in Homebrew's libruby, not the one built with ruby-build.

These are specific for my system. Rbenv paths are shown, but compiling with a different prefix produces same thing.

% readelf -d ~/.rbenv/versions/2.7.1/bin/ruby | grep -F -e libruby -e rpath
 0x0000000000000001 (NEEDED)             Shared library: [libruby.so.2.7]
 0x000000000000000f (RPATH)              Library rpath: [/home/linuxbrew/.linuxbrew/lib:/home/username/.rbenv/versions/2.7.1/lib]

% ldd ~/.rbenv/versions/2.7.1/bin/ruby | grep libruby
         libruby.so.2.7 => /home/linuxbrew/.linuxbrew/lib/libruby.so.2.7 (0x00007f63470d2000)

When the ruby-build ruby is the same MAJOR.MINOR.PATCH as Homebrew's ruby: This wrecks confusing havoc on rubygems, bundler, all the normal toolchain things you would use. Because you start affecting things over in the Homebrew tree instead of where you would expect in the ${PREFIX} used with ruby-build.

When ruby-build's ruby is a different PATCH than Homebrew's ruby, things are more obviously bizarre. Say ruby-build is 2.7.1 and Homebrew is 2.7.0. ruby --version reports Homebrew's ruby version 2.7.0, which seems more like a rbenv, asdf, chruby, env var problem than the actual linker/build problem it is.

Passing --enable-shared=no / --disable-shared to configure addresses all of this. Using a custom ruby-build definition file where I simple removed the enable_shared worked fine. Hoping for a more ergonomic way to do that.

It was a shortsighted decision to enable this option by default. Or rather, not allowing people to disable the shared lib feature.

Was this page helpful?
0 / 5 - 0 ratings