It’s just data

rbenv first impressions

Background: I maintain a scenario that I test against multiple versions of Rails and multiple versions of Ruby.  I primarily develop on Ubuntu, but I bought a new Mac Mini because some of my readers were having installation problems on Snow Lion and my previous mac min can’t install Snow Lion.

Armed with my new Mac Mini, I set off to to repeat my testing of various versions of Rails and Ruby.  Whereas I have been using, and happy with, RVM on Ubuntu for dealing with Ruby versions; I decided to try rbenv/ruby-build.  What I started with was a new machine, a full installation of XCode, the Command Line utilities, and Homebrew.

Keeping my build recipies up to date involves rvm get stable for rvm, and brew update followed by brew upgrade ruby-build' if `brew outdated`.include? 'ruby-build' for rbenv.

Changing to the latest version of 1.9.3 using rvm is accomplished with rvm use 1.9.3.  If the latest version isn’t installed, this will fail, and rvm install 1.9.3 will do the dirty deed.  For rbenv, one needs to first get a list of versions using rbenv install --list, select ones starting with 1.9.3, sort the list numerically by the last digits of the string, and select the largest result.

Building the latest 2.1.0 can be done with rvm install ruby-trunk-nxxx where the -n is optional but useful for tracking multiple “latest” versions.  I use the subversion revision number for xxx.

Building the latest 2.1.0 is where this all goes downhill with rbenv on Mac OS X 1.8.3.  There is a recipe for 2.1.0-dev.  It automatically downloads and builds openssl to workaround a problem if it detects has_broken_mac_openssl.  I like that in a ruby build tool.

Unfortunately, building Ruby 2.1.0 doesn’t work with Apple’s provided version of autoconf, nor does ruby-build automatically know where homebrew puts its version of autoconf.  Adding /usr/local/opt/autoconf/bin explicitly to the PATH allows me to build exactly one version of 2.1.0-dev.  Fortunately, I can rename that directory to add a -rxxx.  Unfortunately, the shims have hardcoded paths in the shebang lines.  Fortunately, a symbolic link compensates for that.  This does mean that in the infrequent event that I want to go back to a prior build of 2.1.0 I need to remember to update the symbolic link too, but I can live with that.

Determining when the previously build “latest” 2.1.0 is no longer current is a matter of finding out where the git checkout of the ruby repository was done to.  For rvm, this is $rvm_path/repos/ruby.  For rbenv, the default is to throw this away, but this default can be overridden using the --keep option, in which case it is saved to $RBENV_ROOT/sources/2.1.0-dev/ruby-2.1.0-dev.  If a git pull in those directories comes up with Already up-to-date., you are golden.  If not, time to rebuild.

Rebuilding with rvm will make use of what I already have.  Rebuilding with rbenv will fail unless I first erase the $RBENV_ROOT/sources directory, after which point it will do a full download of both openssl and a full (albeit shallow) git clone of ruby.

Just when I think I am done, I find out that what works using foreground login sessions via ssh doesn’t work via background sessions like cron or Apache CGI.  Symptoms are that ruby-build downloads and builds openssl, downloads and builds ruby, then complains with: The Ruby openssl extension was not compiled. Missing the OpenSSL lib?.  This took a while to isolate building Ruby 2.1.0 takes a while even with modern hardware.  Ultimately, I determine that the build only succeeds if /usr/sbin is in my PATH.  This makes no sense at all to me, but it works.  Moving on...

At this point, I have everything working, but it certainly isn’t pretty.  Time to refactor.

One way to approach this is to move all of this logic to a rbenv plugin.  rbenv whatis is a step in this direction.

A better approach would be to first see which parts of this I could either motivate to get fixed in rbenv itself, perhaps even contributing code myself.  The first step is to start a dialog with the developers, but alas I can find no IRC channel or mailing list.  I see that others have resorted to using the issue tracker for this, but that doesn’t seem quite appropriate for this grab bag of small issues and WIBNIs I have at this point.

A prioritized wish list to start with:

It is indeed possible that I overlooked something and/or one or more of these are user errors on my part.  If so, pointers would be welcome.

Whatever is not done, I can put into a rbenv get or equivalent command which does whatever is necessary under the covers to switch to the specified version, including build it if necessary.


Hi Sam,

Thanks for the post—it’s always helpful to see things from a fresh perspective.

First let me say that rbenv’s command-line interface is not optimized for your use case of automatically testing an app or library on multiple versions of Ruby. (Not to say it isn’t possible, or that we shouldn’t improve it, just that it isn’t rbenv’s primary focus.)

Rather, rbenv is optimized for enforcing a precisely specified Ruby version for each application on your system, ensuring your apps have the same environment in development and production. In rbenv’s world, changing an app’s Ruby version is a deliberate act, which is why there’s no support for things like fuzzy version matching ("give me the latest 1.9.3").

I’ll address your suggestions one-by-one:

“If a source is already downloaded or cloned, use it.” If you create an `~/.rbenv/cache` directory, `rbenv install` will cache downloaded packages there. I’m hesitant to automatically create this directory because it will accumulate junk over time, but perhaps that’s not a real issue.

“Allow me to provide an additional revision number when building 2.1.0-dev.  Either that or automatically do this for me.” Great idea. I’d welcome a patch to ruby-build with this functionality.

“If homebrew has installed a later version of autoconf, use it in preference to the Apple provided version.” I don’t have an Apple-provided version of autoconf on my system. Did you perhaps install another package that provides it? Adjusting your path so `/usr/local/bin` comes before `/usr/bin` (assuming that’s where the other autoconf is) should fix the problem. If the issue is widespread, then perhaps ruby-build should be modified to search for a newer version of autoconf.

“Figure out what is needed in /usr/sbin and either avoid it or make sure that it is found.” Haven’t heard of this before. What led you to determine you need `/usr/sbin` in your path?

As for where to discuss these sorts of issues, I actually think a blog post like yours is a fine medium. Individual tickets on the issue tracker would also be a good way to get things rolling. For smaller questions, I am always available on Twitter at @sstephenson.

Posted by Sam Stephenson at

First let me say that rbenv’s command-line interface is not optimized for your use case of automatically testing an app or library on multiple versions of Ruby. (Not to say it isn’t possible, or that we shouldn’t improve it, just that it isn’t rbenv’s primary focus.)

Fair enough.  Focus is good.  That being said, error messages such as the following aren’t exactly welcoming to newcomers:

ruby-build: definition not found: 1.9.3

Perhaps some heuristics could be added to see if there is a fuzzy match and make a suggestion (for example, suggesting 1.9.3-p392)

But as to my use case, rbenv provides a solid enough foundation that I can build a higher level management system upon.

“If a source is already downloaded or cloned, use it.” If you create an `~/.rbenv/cache` directory, `rbenv install` will cache downloaded packages there. I’m hesitant to automatically create this directory because it will accumulate junk over time, but perhaps that’s not a real issue.

A cache would indeed help.  In my case, the time it takes to download openssl isn’t large compared to the time it takes to build it.  So what I’m more looking for is something akin to ‘make’ in that it doesn’t reproduce steps that have already been done.

“Allow me to provide an additional revision number when building 2.1.0-dev.  Either that or automatically do this for me.” Great idea. I’d welcome a patch to ruby-build with this functionality.

Will look into.

“If homebrew has installed a later version of autoconf, use it in preference to the Apple provided version.” I don’t have an Apple-provided version of autoconf on my system. Did you perhaps install another package that provides it? Adjusting your path so `/usr/local/bin` comes before `/usr/bin` (assuming that’s where the other autoconf is) should fix the problem. If the issue is widespread, then perhaps ruby-build should be modified to search for a newer version of autoconf.

The problem indeed was that /usr/local/bin was later in my path.

“Figure out what is needed in /usr/sbin and either avoid it or make sure that it is found.” Haven’t heard of this before. What led you to determine you need `/usr/sbin` in your path?

By trial and error.  More detail:

$ export PATH=`echo $PATH | sed -e 's/:\/usr\/sbin//'`
$ ruby
<internal:gem_prelude>:1:in `require': cannot load such file -- rubygems.rb (LoadError)
	from <internal:gem_prelude>:1:in `<compiled>'

This ultimately (and unsurprisingly) leads to the following error:

executable host ruby is required. use --with-baseruby option.

I’ll try to research further.

Individual tickets on the issue tracker would also be a good way to get things rolling.

If/when I have concrete suggestions and/or patches to propose, I’ll do that.

Thanks for the feedback!

Posted by Sam Ruby at

That being said, error messages such as the following aren’t exactly welcoming to newcomers: … Perhaps some heuristics could be added to see if there is a fuzzy match and make a suggestion (for example, suggesting 1.9.3-p392)

You’re absolutely right. That’s a very unfriendly message. I’ve just implemented your suggestion in ruby-build.

Posted by Sam Stephenson at

I’ve started a separate thread on changing share/ruby-build/*-dev to build a specific revision.

Posted by Sam Ruby at

In actual fact loaded content and awfully positive information. I got it my way out from over here. I greatly propose his/her works with the functional informative information. Thanks a lot………..

Posted by ecift.com at

Add your comment