Skip to main content



What is it

GNU Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files.

In plain terms, Make is a language-agnostic tool used for building things.

When to use it

Building Go projects

Our Go projects typically use a Makefile at the root of the project, whose default target runs the full set of CI build steps and checks for the project.

How to get it

Make is already pre-installed on Ubuntu (recommended).


OSX users can use a Homebrew formula to install GNU Make. Make sure to follow the instructions on replacing the default make with gmake.

How to learn it

Run through the excellent Makefile Tutorial.


Strictly follow the Rules of Makefiles and take as much inspiration as possible from Clark Grubb's Makefile style guide.

The tools/ directory

Our Make projects with dependencies on external build tools (for example command line tools that are required as part of the build) typically use a tools/ directory to modularize and simplify managament tooling dependencies.

The typical high-level structure of the tools/ directory is:

├── tool-1
│   ├── 0.41.0
│   ├── 0.42.0
│   └──
├── tool-2
│   ├── 0.7.0
│   └──
└── tool-n
├── 1.2.3

Every subdirectory of tools/ contains Make rules for a specific tool, and that subdirectory always contains a with the rules needed to download and/or build that specific tool.


Since Make puts variables from all included files into a common global namespace, files should prefix all variables with the name of the tool itself to minimize variable naming conflicts.


An annotated example file for the Buf CLI:

# 1) The parent directory
buf_cwd := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
# 2) The tool version
buf_version := 0.56.0
# 3) Path to the tool executable
buf := $(buf_cwd)/$(buf_version)/bin/buf

# 4) URL for downloading the tool
buf_bin_url :=$(buf_version)/buf-$(shell uname -s)-$(shell uname -m)

# 5) Make rule for downloading the tool
$(buf): $(buf_cwd)/
$(info [buf] feching version $(buf_version)...)
@mkdir -p $(dir $@)
@curl -sSL $(buf_bin_url) -o $@
@chmod +x $@
@touch $@
1) The parent directory

The <tool>_cwd variable is initialized to the current working directory (cwd) of the tool.

$(abspath $(dir $(lastword $(MAKEFILE_LIST)))) is a Make-ism for "the directory of the current Make file".

2) The tool version

Updating the <tool>_version variable should be all that is needed when upgrading to a newer version of the tool.

3) The Path to the tool exectuable

The <tool> variable contains the absolute path to the current version of the tool binary and will be used to invoke the tool in the parent Makefile.

4) URL for downloading the tool

Use the output of the uname command to fetch the correct distribution of the tool for your OS and CPU architecture.

5) Make rule for downloading the tool

The Make rule for the <tool> variable fetches, unpacks and updates the modified timestamp of the tool binary.

The rule depends on $(<tool>_cwd)/ to ensure that modifying the rule itself causes the rule to be re-run.