[A while ago](https://fieldnotes.tech/2019/07/04/how-to-shell-for-compatible-makefiles/) I documented a robust-ish way to set up the `SHELL` in a Makefile.
Time has moved on and I’ve learned how to:
- Make effective use of parallelism (so I now include `MAKEFLAGS += --jobs=8` most of the time.
- Write neater recipes using `.ONESHELL`
- Implement some “standard” starter targets for Go projects:
- `make compile` to [quickly check _everything_ compiles correctly](https://fieldnotes.tech/2023/02/11/compiling-all-test-binaries-without-running-them/)
- `make test` to run the tests, with minimal output.
- `make install` to install binaries `make install`
In order to support all this, we now need to switch the shell setup based on the version of GNU Make we’re using. For some reason `.ONESHELL` confuses things in this regard otherwise.
You can see the most up-to-date version of this template at [samsalisbury/home](#)
Here’s how it looks at the moment:
```Makefile
.ONESHELL:
# Make on macOS is stuck at 3.81
ifeq ($(MAKE_VERSION),3.81)
SHELL := /usr/bin/env bash -euo pipefail -c
else
SHELL := /usr/bin/env
.SHELLFLAGS = -euo pipefail -c
endif
MAKEFLAGS += --silent --jobs=8
QUIET_UNLESS_FAIL = OUT="$($2 2>&1)" || { CODE="$?"; printf "$1 failed:\n%s" "$OUT"; exit $CODE; }; echo "$1: OK"
default: test
.PHONY: default
# -----
# Section: Go General
# This section should be useful for all go projects.
# -----
ALL_PACKAGES := ./...
compile:
$(call QUIET_UNLESS_FAIL,Compilation, go build $(ALL_PACKAGES))
$(call QUIET_UNLESS_FAIL,Test compilation, go test -exec true $(ALL_PACKAGES))
.PHONY: compile
test: compile
$(call QUIET_UNLESS_FAIL,Running go tests, go test $(ALL_PACKAGES))
.PHONY: test
# -----
# Section: Go Executable.
# This section is useful for go projects creating an executable.
# -----
NAME := hc-gh
# BIN is the binary name.
BIN := ./$(NAME)
# DESTDIR is the absolute path to the install path if running 'make install'
# Default to wherever it's currently installed using which, or /usr/local/bin
# if it's not yet installed.
DESTDIR ?= $(shell $(dirname $(which $(NAME)) 2>/dev/null || echo /usr/local/bin)
build: $(BIN)
echo
lt;
.PHONY: build
$(BIN): test
go build -o "$@"
.PHONY: $(BIN)
install: $(BIN)
mkdir -p "$(DESTDIR)"
install "$(BIN)" "$(DESTDIR)"
.PHONY: install
```
#FieldNotes.Tech/posts
#FieldNotes.Tech/collections/categories/how-to
#FieldNotes.Tech/collections/tags/makefile