Conditionally Bundling Gems Based on Platform

There are a couple of libraries which I usually include in my Gemfiles because they make Guard more awesome on Ubuntu. However, they don’t make sense to require on other platforms, and they probably don’t even compile when not on Linux.

As far as I can tell, there’s no “official” way to conditionally include gems in a Gemfile based on the current OS platform. Or at least there wasn’t the last time I looked at the Bundler documentation. Fortunately a Gemfile is just Ruby, so that’s not really a limitation.

So here’s what I put in my Gemfile:

group :test, :development do
  # ...
  gem 'rb-inotify' if RUBY_PLATFORM =~ /linux/i
  gem 'libnotify' if RUBY_PLATFORM =~ /linux/i
end

This works well for me, but if there’s a better way I’d love to know it.

13 comments

  1. The bundler manual has this on the Gemfile (read this: http://gembundler.com/man/gemfile.5.html):

    As with groups, you can specify one or more platforms:
    gem "weakling", :platforms => :jruby ,(...)
    

    This probably means that you might be able to use something like:

    platforms :jruby, :mri_1.9 do
      gem "weakling"
      gem "hookah"
    end
    

    Hope to have helped.

  2. What you want is: “gem ‘libnotify’, :require => false”

    An example is at https://gist.github.com/3843679

    These libraries will be installed, but won’t be required and therefore won’t bork other platforms.
    The method you have above, which I’m sure you are aware, will cause the Gemfile.lock file to change depending on which platform you run “bundle install” on.
    Ciao!

  3. I usually use Gemfile groups for these, like:

    gem ‘rb-inotify’, :group => :linux

    When I install gems, I have to specify –without in order to not install those gems, but this works well. Using if statements in the Gemfile will cause your Gemfile.lock to be generated with the logic of the platform you last ran bundle upgrade on.

  4. Hi Avdi, I had problems with this approach when using it with Capistrano for deployment. Didn’t you encounter similar problems?
    I needed some platform specific gems for OSX (growl, terminal-notifier) and some platform specific for Linux, so as an alternative to using plain old ruby conditionals, I put it in a :osx and a :linux group and excluded :linux on osx with bundle install –without linux and vice versa. But this is not a clean solution, so I think it would be very useful to have native support in bundler, to manage platform specific gems.

    1. What always trips me with this is that on OSX i need bundler to install let’s say the fs-event gem and it then writes it to Gemfile.lock, but when I deploy to a Linux system it will cry as fs-event is in Gemfile.lock but not available on Linux.
      Any solutions to that problem?

  5. As others have said, the remaining issue is how to manage the Gemfile.lock. Have you found a solution? it would be nice if there were a way to specify the location of the Gemfile.lock and change it based on the platform, but last I checked the code’s highly coupled to the naming convention.

Leave a Reply

Your email address will not be published. Required fields are marked *