bundle install and then, a few minutes later, your terminal spits up an ugly set of C compiler errors you don’t know how to deal with. After dealing with this enough times I decided to do something about it.
Homebrew already has a great tool in its arsenal for dealing with these problems. Homebrew needs to be able to build software reliably and robustly, after all - even if the user’s system has weird software installed on it or strange misconfigurations. The “superenv” build environment features intelligent automatic setup of build-related environment variables and
PATHs based on just the requested dependencies, which filters out unrequested software and prevents a lot of common build failures that come from interfering software. It also uses shims for many common build tools to enforce just the right arguments passing through to the real tools.
So I thought to myself - we solved that problem for Homebrew builds already, right? Wouldn’t it be nice if I could just reuse that work for other things? So that’s what I did. Homebrew already provides the
Brewfile dependency declaration format and the
brew bundle tool to library dependencies with Homebrew, and as a result there’s already a great way to get the dependency information we’d need to produce a reliable build environment. Since
brew bundle is a Homebrew plugin, it has access to Homebrew’s core code - including build environment setup. Putting these together, I wrote a feature called
brew bundle exec. It takes the software you specify in your Brewfile and builds a dependency tree out of that, then sets up just the right build flags to let anything you want use them.
For example, say I want to
gem install mysql2. Often, you get something like this:
1 2 3 4 5 6 7
Ew, right? Let’s make that better.
By creating a
Brewfile with the line
brew "mysql", we can specify that we want to build against a Homebrew-installed MySQL and all of its dependencies. Just by running our command prefixed with
brew bundle exec --, for example,
brew bundle exec -- gem install mysql2, we can run that command in a build environment that knows exactly how to use its dependencies. Suddenly, everything works—no messing around with flags, no special options passed to
gem install, and no fragile
bundle config trickery.
1 2 3 4 5 6 7
What exactly does
brew bundle exec set? There’s a variety of flags set which are useful for a variety of different compilers and buildsystems.
CXX, the compiler specification flags, point to Homebrew’s compiler shims which help ensure that the right flags are passed to the real compiler being used.
CPPFLAGSensure that C and C++ compilers know about the header and library lookup paths for all of the
PATHensures that all of the executables installed by
Brewfiledependencies will be found first, before any tools of the same name that may be installed elsewhere on your system.
PKG_CONFIG_LIBDIRensure that the
- Buildsystem-specific flags, such as
CMAKE_PREFIX_PATH, ensure that buildsystems can make use of the
So the next time you’re bashing your head against build failures in your project, give
brew bundle exec a try. It might just solve your problems for you!