Barrel is a portable, header-only C++ library that provides programmatic access to the Homebrew command line interface.
It is intended to help build generic, non-trivial wrappers around Homebrew. For example, using Barrel, you could write a feature-rich GUI frontend for Homebrew on macOS. Or it could be used to develop bespoke tooling to customize/automate Homebrew-based package configuration for your CI/CD jobs. Or it could help you work with homebrew on headless systems.
tl;dr: Use Barrel whenever you want to interact with Homebrew and the shell interface just doesn't cut it.
Barrel is highly performant, with almost no runtime overhead (see benchmarks). It exposes a well documented, succinct C++ API (see reference) which can be integrated with a wide variety of libraries, tools and frameworks (see examples).
#include <Barrel/barrel.h>
#include <iostream>
int main(int argc, char** argv) {
Brew brew;
std::cout << brew.getInstallPath(); // /usr/local/bin/brew
std::cout << brew.getInstallVersion(); // Homebrew 3.5.4
BrewCommand<BrewCommandType::Builtin> cmd(brew, BrewCommandType::Builtin::INFO);
cmd.execute();
std::cout << cmd.getExitStatus(); // 0
std::cout << cmd.getStreamDump(); // 120 kegs, 75,556 files, 1.8GB
return 0;
}
This is the "Hello, World!" equivalent of using Barrel. It creates a default brew
object to set up Homebrew execution environment, then creates a cmd
object to execute the command brew info
, and finally prints the exit status and output of the executed command.
-
Header-only; no need to build before using
-
Self contained; no external dependencies
-
Readable, modern C++ source; easy to modify if needed
-
Negligible runtime overhead
-
Powerful ways to interact with Homebrew:
- Validate and configure your Homebrew installation
- Chain and execute any arbitrary
brew
command (except those which read fromstdin
interactively, if any) - Capture exit status, and
stdout
,stderr
, or both - Execute long running
brew
commands asynchronously (with support for early binding/delayed invocation) [1] - Live-capture/poll output stream (
stdout
/stderr
) data from abrew
command as it is being generated [2] - Execute
brew
commands on multiple threads on multi-core machines
Now let's take a look at another example which shows how a client can use some of the advanced functionality offered by Barrel.
Barrel is a header-only library, written in C++20. Using it can be as simple as copying the include/
directory in your project and importing the primary header like "include/barrel.h"
. In most cases, however, you'd want to use a build system like GNU Make/Ninja, and a build automation tool like CMake to manage building your project.
Further, you need an installation of Homebrew. Barrel does not install Homebrew for you. A brew
binary must be available somewhere in your environment before using Barrel, although it is not necessary for it to be present in $PATH
.
- macOS (10.15 or higher)
- Homebrew (requirements)
- A C++ compiler (C++20 or higher) and the accompanying toolchain
- Make
- CMake (3.15 or higher)
-
Get the source (
git clone
for the latest developmental version, or get a versioned release) -
Build Barrel
mkdir build && cd $_
cmake ..
cmake --build . --target install
These steps do the following: 1. Create and enter a
build
directory in the project root, 2. Configure the project and prepare a build configuration for the actual build system (Make in my case), and 3. Call Make to build Barrel (by compiling/linking however specified), executing the predefinedinstall
target to install the library. You should see aninstall/
directory in the project root after step 3. Since Barrel is header-only, all the sources ininclude/
simply get copied over toinstall/Barrel/include/
.
Alternatively, you could download a pre-built archive.
Link to Barrel from your project:
-
As an external dependency
Say you have a project you want to include Barrel in, but you do not want to add Barrel to your project's source tree. In this case, you can include Barrel as an external dependency after building it.
CMake
find_package
makes it straightforward. I have included a simple CMakeLists.txt example you can consult atexamples/external/CMakeLists.txt
. -
As an internal dependency
- Project Logo: Vecteezy
- Documentation Generator: Doxygen
- Documentation Stylesheet: Doxygen Awesome
- Documentation Host: GitHub Pages
- CI Server: CircleCI