A crafty, nommy, occassionally geeky blog-thing.

Things They Don't Tell You: Ruby Gems Need to Be Compiled!

So I’ve been revisiting ruby, revisiting Rails, and, natch, revisiting that Rails Starter App. Rails has been growing like the toddler; so many many things are different. No one “rake freeze:gems” anymore, furinst. Now, its all “config.gem ‘blah’” this and “rake gems:install” that. Makes the head dizzy.

So I’ve got la in my preferment’s config/environment.rb:

config.gem "hpricot", :version => '>=0.6', :source => ""
config.gem "sqlite3-ruby", :lib => "sqlite3"
config.gem "haml", :version => '>=2.1.0'
config.gem "RedCloth", :verion => '>=4.1.9'

And dutifully I’ve run “rake gems:install; rake gems:update” to (1) install those bad boys, and (2) roll them directly in to my app. For larks, I also gem-uninstalled the versions of the gems that were put in my GEM PATH. Just to convince myself that my preferment really was using the vendor’ed ones.

And it was.

Lastly, I git-committed the whole shebang (vendor and all), for future cloning fun. Thinking how clever — with the vendor’ed gems right there, I won’t even need to re-download all that crap when I fork future apps offa this.

Later, I cloned it out to my laptop, and let the woe begin. Rake was not a happy camper. It kept complaining that required gems (as listed in environment.rb) were missing. Like heck! I could see them right there in /vendor/gems/. But, you know, if ruby wants to be pissy about it, fine — go ahead and re-install — “rake gems:install”. Rake spews screens of “stuff”, but ultimately says yes, it installed those gems, yes, its happy. Except the next time I run it, it does the whole thing again. And again. And again.

Now, the astute will notice that I did not first delete the the copy of the gem that was vendor’ed. If I had, my heart would ache less, I wouldn’t have wasted the last 21 days on this, and I wouldn’t have learned a durned thing. Go hard knocks.

Now most of the rake gems bits floating around the intertubes just talk about gems:install and gems:unpack as the two methods you need to know. Here’s the dirty dark secret. They are lying to you. Gems can be chock full of “native extensions” which is fancy talk for code that needs to be compiled. Now (and I could be helplessly wrong about this coming bit, but here’s how it seems), if you are running rails on the same platform (say OS X) as the gem was developed on (say OS X), you may never notice this; you may automatically download a pre-compiled version that just works. But if you’re on some other platform (say a flavour of linux) when the gem was developed on something else (say OS X), what you download when you “rake gems:install” isn’t ready to rock yet. You need to “rake gems:build” first. How do you know if you need to build those native extensions? You know because ruby insists your gem isn’t installed yet. You know because if you try to install it again, rake spews all over your screen. That spew begins with “no such file to load — {gemname}_scan”, and ends with rake telling you the gem has been installed. My take-home — if you installed a gem and it doesn’t work out of the box, just assume it has “native extensions” which need to be “built”.

And here’s where things get trickier. That bit which got “installed” when you “rake gems:install”-ed will be different depending upon which OS you installed it under. “rake gems:install” on OS X gets you aslightly different files than “rake gems:install” on CentOS. More to the point, you can’t “rake gems:build” in linux a gem that was “rake gems:install”-ed in OS X.

So don’t include your /vendor/gems when committing or deploying! Just don’t. Dummy.

Stay tuned for tomorrow’s exciting post: we bought an exciting new salt grater on the weekend which is now dull and useless, because we used it to… you’ll have to read tomorrow to find out!

  1. Yes, 2. I’m a dummy. And, in my defense, really slow sometimes. But seriously, I “script” because I can’t be bothered to “compile”. So don’t expect me to know this stuff. D’uh!