The Missing Guide to Porting Software to Homebrew

I've been a casual Homebrew user for a long time but first time packager. While looking around on the net, I was not able to find some guidance on how to start porting my software quickly. Many resources point people to start creating a formula. After some frustration, I realized a formula is packaging the software. It does not sound like the right first task. I would first want to build my project and clear any compile errors.

Homebrew has a "manual install" mode that seems to suit my need. I could focus on sorting out compile errors and change codes quickly. Once having built and run the binary successfully, then move on to creating a formula. The purpose of this article is to outline repetitive steps I use to clear all hurdles, up to the point of first successful compilation and run.

This guide won't touch on fixing compile errors nor best practices of portable codes. If you understand the above paragraphs and work on building software from command line before, you already get the essence. There is only tiny bit of Homebrew stuff. I use my pixelserv-tls as an example. Let's dwell into details.

Manual Compile

Open a Terminal and get the source code of pixelserv-tls. Unarchive locally. Here are all the commands:

$ wget
$ tar xzf 2.2.0.tar.gz
$ cd pixelserv-tls-2.2.0

Now, check what tools are needed for the build. Looking at Build from source on pixelserv-tls' Github, we need "make," "automake" and "autoconf". On macOS, "make" comes as part of Xcode command line tools. If you're a Homebrew user, the command line tools should have been installed already. Otherwise, follow this guide to install.

Additionally you could follow these instructions to install the full Xcode (which doesn't include the command line tools). pixelserv-tls does not require the full version but a few Homebrew packages need it.

For pixelserv-tls, I install "automake" and "autoconf" from Homebrew:

$ brew install automake
$ brew install autoconf

Now let's try to run the first build command.

$ cd pixelserv-tls-2.2.0
$ autoreconf -i

It finishes successfully. Try to run the next build command "./configure." No errors again but I'm fairly sure the result won't be right. Check the library dependencies for pixelserv-tls by reading I'll need "OpenSSL," "pthread," and "rt" libraries.

"pthread" and "rt" come with macOS, part of "/usr/lib/libSystem.B.dylib." macOS also bundles a very old version of "OpenSSL" which isn't useful for any modern projects. But Homebrew uses it as default unless something else specified at build time.

Homebrew has two "OpenSSL" packages (as of this writing) in its core repository, versions 1.0 and 1.1. Both versions work for pixelserv-tls. Since versions >= 1.1.1 provide TLS 1.3 support, I would pick v1.1:

$ brew install openssl\@1.1

We then need to tell the build script where to look for the correct header and library files. To work out the paths is easy after you look at one or two examples in Homebrew's cellar. There is a way to change the Homebrew default but let's not digress in this post. So I pass the paths to the build script:

$ ./configure CFLAGS='-I/usr/local/Cellar/openssl\@1.1/1.1.1/include' LDFLAGS='-L/usr/local/opt/openssl\@1.1/lib'

Run it again. It completes successfully. Now proceed to the last build command:

$ make

Unfortunately as expected, I could see quite a few compile errors. But finally I could engage in an iterative process to fix those errors. If you follow my approach, pretty fast to get on the real job. pixelserv-tls is a tiny server application. Compile errors are quick to fix. Try manually run it as documented its Github. Not unexpected, there are more run-time issues. So after another round of iterative process of debugging but more challenging this time, I eventually worked out a set of good changes.

Manual Install

Homebrew allows users to manually install binaries and etc into its cellar. To do so, unwind the steps a bit. Before the very first step, we run the following additional command to get "--prefix."

$ cd pixelserv-tls-2.2.0
$ brew diy

"brew diy" could guess project name and version based on the name of the directory holding the source tree. Note that I believe the directory name has to be in the format of "<project name>-<version>" in order for "brew diy" to get it correctly. Now we re-work two build commands in the previous steps:

$ ./configure --prefix=/usr/local/Cellar/pixelserv-tls/2.2.0 CFLAGS='-I/usr/local/Cellar/openssl\@1.1/1.1.1/include' LDFLAGS='-L/usr/local/opt/openssl\@1.1/lib'
$ make install

"make install" will compile pixelserv-tls (if necessary) and install the binary, manpage and other pixelserv-tls files into the cellar location pointed to by "--prefix". The final step is to create symlinks in Homebrew's default paths. So that type "pixelserv-tls" will run it without specifying full path.

$ brew link pixelserv-tls

For completeness, to undo manual installation:

$ brew unlink pixelserv-tls
$ rm -rf /usr/local/Cellar/pixelserv-tls

So far we have prepared the project for packaging. We even have tested manual install which is optional but good try anyway. In the next article, I will go through creating a formula for pixelserv-tls.

Stay tuned.

The second part of the guide: Creating Homebrew Formulae.

comments powered by Disqus