Using GNU utils on Macs for Makefile compatibility

By on September 12, 2018 - Geekery Tags:

One problem I see often with local builds are Makefiles that use modern GNU features in common commands like sed, awk, and tar. If the product only runs on Linux, writing backwards compatible versions for the older BSD-based commands on Macs may not be an effective use of time.

A simple fix is to libexec/gnubin directory to your path as documented here: Install and Use GNU Command Line Tools on macOS. However this changes your active environment, which might break scripts expecting to run on macOS. Further, this isn’t a repeatable configuration that can be safely used by others.

A better way is to explicitly configure the GNU versions to ensure they are used during the build. Shown here is a Makefile snippet that can be included to add the specified utilities to the path only while running make:

# On Mac OS X, require GNU versions of programs instead of dealing with BSD utility incompatibility
ifeq ($(shell uname),Darwin)

# These can be set to a smaller or larger list in the project Makefile
BREWPKGS ?= make coreutils findutils gawk grep gnu-getopt gnu-indent gnu-sed gnu-tar gnutls gpatch m4

define BREW_HAS_INSTALLED
    ifeq ($(shell brew ls --versions $1),)
        $$(error Missing package $1 from Homebrew [http://brew.sh]. Please run: `brew install $1`)
    else
        PATH := $(shell brew --prefix $1)/libexec/gnubin:$(PATH)
    endif
endef

# Iterate through packages
ignore:= $(foreach pkg, $(BREWPKGS), $(eval $(call BREW_HAS_INSTALLED,${pkg})))

# /Darwin
endif

I found this idea in a Makefile in HazyResearch/deepdive and tweaked it to handle all the necessary packages.