Apr 12, 2009

Multiple Versions of Ruby on Ubuntu #3



This post is from a time before RVM or rbenv you should check out those instead..

I decided it's time to switch to Ruby 1.9 but I still have a couple of Ruby 1.8 projects I need to maintain. That means I need a simple technique for switching back and forth between multiple versions of Ruby. I've experimented with different approaches in the past but I'm not completely satisfied with any of them.

This time I've decided to use a shell script to update a symbolic link that points to the active version. It's extremely fast and simple.

I started by purging my system of any apt installed Ruby packages.
sudo apt-get remove --purge ruby1.8 ruby1.9

Then I installed Ruby 1.8 from source.
sudo apt-get build-dep ruby1.8
wget -c ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p72.tar.gz
tar -xvzf ruby-1.8.7-p72.tar.gz
cd ruby-1.8.7-p72
./configure --prefix=/opt/ruby-1.8.7-p72 --enable-pthread --enable-shared --enable-openssl --enable-readline --enable-zlib
make
sudo make install
wget -c http://rubyforge.org/frs/download.php/45905/rubygems-1.3.1.tgz
tar -xvzf rubygems-1.3.1.tgz
cd rubygems-1.3.1
sudo /opt/ruby-1.8.7-p72/bin/ruby setup.rb

Then I installed Ruby 1.9 from source.
sudo apt-get build-dep ruby1.9
wget -c ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p0.tar.gz
tar -xvzf ruby-1.9.1-p0.tar.gz
cd ruby-1.9.1-p0/
./configure --prefix=/opt/ruby-1.9.1-p0 --enable-pthread --enable-shared
make
sudo make install

Then I add the following line to the bottom of $HOME/.bashrc
export PATH=/opt/ruby/bin:$PATH

Then I saved the following script in /usr/local/bin/select_ruby
#!/bin/sh

while : # Loop forever
do
cat << !

current = $(/opt/ruby/bin/ruby --version)

Select Option

1. ruby-1.8.6-p368
2. ruby-1.8.7-p72
3. ruby-1.8.7-p160
4. ruby-1.9.1-p0
5. exit

!

echo -n " Your choice? : "
read choice

case $choice in
1) rm -rf /opt/ruby; ln -s /opt/ruby-1.8.6-p368 /opt/ruby;;
2) rm -rf /opt/ruby; ln -s /opt/ruby-1.8.7-p72 /opt/ruby;;
3) rm -rf /opt/ruby; ln -s /opt/ruby-1.8.7-p160 /opt/ruby;;
4) rm -rf /opt/ruby; ln -s /opt/ruby-1.9.1-p0 /opt/ruby;;
5) exit;;
*) echo "\"$choice\" is not valid "; sleep 2 ;;
esac
exit
done

Now to switch I just run the script and select the version I want.
sudo select_ruby

There's a couple of things to be aware of using this approach. Each ruby installation has it's own separate instance of rubygems so gems will have to be installed multiple times. Also since sudo doesn't preserve the users $PATH you will need to use the full path with the gem command; example:
sudo /opt/ruby/bin/gem install rails
Or this fix.

16 comments:

Luan Nguyen said...

When I type command:

sudo gem install sequel
sudo: unable to execute /usr/bin/gem: No such file or directory

I got the unable to execute /usr/bin/gem. How do I get rid of this error.

Thanks,
Luan

Luan Nguyen said...

I didn't get this error anymore. I had other terminal open while I installed new ruby 1.9.

Thanks for your example on how to install both ruby versions. It works fine for me now.

Luan

Aaron said...

running 'sudo select_ruby' returns:

/usr/local/bin/select_ruby: 5: Syntax error: ")" unexpected (expecting "done")

Unknown said...

Aaron: Sorry about that. Blogger has a habit of munging the html of it's posts and stripping out line endings where it shouldn't. I updated the script.

Paul Carey said...

Thanks for the series of posts.

I've no experience with update-alternatives, but it seems like it was written specifically to solve this problem. You said you weren't satisfied with it. Could you explain why?

Thanks

Paul

Aaron said...

Thanks Michael. The select_ruby script now works like a charm :)

oren said...

thanks for this guide!

btw, if i want newer rubygems for each of the versions, i can simply compile it on top of the existing ones?

oren said...

I have issues with rake and cucumber:

when I type rake or cucumber I get:

/usr/bin/rake: /usr/bin/ruby1.8: bad interpreter: No such file or directory

Unknown said...

Oren: You're clearly having path issues. The entire setup I've described depends on having the symbolic link '/opt/ruby' come before any other Ruby executables in your $PATH.

I'd start by inspect $PATH.

If you still have troubles after that let me know.

oren said...

thanks,
I had this line, but not identical..it works now.

one more question - to get recent ruby (1.9.1-p243),
do I need to remove the folder /opt/ruby-1.9.1-p0
and install the new one instead?

Thanks again

Unknown said...

Oren: you don't need to remove the folder, but you can. You can either simply change all occurrences of ruby-1.9.1-p0 in the existing script with 1.9.1-p243 or as an alternative you could simply add the additional version.

If you're going to add it you'll want to make changes like this....

4. ruby-1.9.1-p0
5. ruby-1.9.1-p243
6. exit

and

4) rm -rf /opt/ruby; ln -s /opt/ruby-1.9.1-p0 /opt/ruby;;
5) rm -rf /opt/ruby; ln -s /opt/ruby-1.9.1-p243 /opt/ruby;;
6) exit;;

Tom Cloyd MS MA said...

Michael, thanks so much for these very clear instructions. With modifications to reflect new versions, I was successful in installing 1.8.7 from source. Will move on to 1.9.1 in a bit. I blew 9 hours yesterday trying to do this with a slightly different approach, and failed. I'm grateful to be successful today. It was your level of detail that made the difference. Much gratitude!

IcyCold said...

Micheal thanks for your instructions.. a minor enhancement which i use.. just thought i should share.

Adding ruby -v at the end; ensures that the correct ruby version was selected.

1) sudo rm -rf /opt/ruby; sudo ln -s /opt/ruby-1.8.7-p72 /opt/ruby; ruby -v;;
2) sudo rm -rf /opt/ruby; sudo ln -s /opt/ruby-1.9.1-p243 /opt/ruby; ruby -v;;

Ouput looks like:

Your choice? : 1
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-linux]

-Ritesh

Nirbhab said...

Excellent Blog

apnnews said...

After Executing make command, I am receiving following error

root@ruby-dev:/home/apandya/Downloads/ruby-1.8.6-p111# make
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c array.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c bignum.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c class.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c compar.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c dir.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c dln.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c enum.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c error.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c eval.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c file.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c gc.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c hash.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c inits.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c io.c
io.c: In function ‘appendline’:
io.c:1546: warning: ignoring return value of ‘fread’, declared with attribute warn_unused_result
io.c: In function ‘next_argv’:
io.c:4467: warning: ignoring return value of ‘fchown’, declared with attribute warn_unused_result
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c marshal.c
gcc -g -O2 -fPIC -DRUBY_EXPORT -D_GNU_SOURCE=1 -I. -I. -c math.c
math.c:37:13: error: missing binary operator before token "("
make: *** [math.o] Error 1

apnnews said...

On Make Command, I am facing following error

math.c:37:13: error: missing binary operator before token "("
make: *** [math.o] Error 1

Any Help? I am using Ubuntu 9.10 on X86_64

Thank You
Amit