Makefile Portable POSIX Patterns

Portable makefile patterns that work across POSIX make environments, avoiding GNU-only features when needed.

View
StandardDetailedCompact
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all

Portable make basics

Patterns that avoid GNU-only behavior.

POSIX-style portable rule

Write simple, explicit file rules compatible with standard make.

makefileANYposixportablerules
makefile
all: app

app: main.o util.o
  cc -o app main.o util.o

Explicit rules are the most portable foundation.

Use standard macros

Honor user-overridable standard compiler variables.

makefileANYposixportablevariables
makefile
CC = c99
CFLAGS = -O2
LDFLAGS =
LDLIBS =

app: main.o util.o
  $(CC) $(LDFLAGS) -o $@ main.o util.o $(LDLIBS)

Keeping `CC`, `CFLAGS`, `LDFLAGS`, and `LDLIBS` overridable is a long-standing portable convention.

Suffix rule

Use classic suffix rules when targeting very portable make implementations.

makefileANYposixsuffix-rules
makefile
.SUFFIXES: .c .o
.c.o:
  $(CC) $(CFLAGS) -c $<

Suffix rules are older but widely portable.

Portable clean target

Provide common non-file maintenance targets.

makefileANYposixcleanportable
makefile
clean:
  rm -f app *.o

`.PHONY` is common in modern makes, but some historical portability guidance prefers not to depend on it unless you know the implementation supports it.

Override variables from CLI

Allow users to customize toolchain choices.

bashANYposixclivariables
bash
make CC=clang CFLAGS='-O0 -g'

Command-line macro assignments are part of standard make usage.

Recipe portability

Shell-safe and cross-environment recipe habits.

Use shell short-circuit safely

Stop on failure explicitly within one recipe line.

makefileANYportableshellrecipes
makefile
deploy:
  cd infra && terraform apply -auto-approve

Since each recipe line runs in its own shell by default, keep dependent shell commands on the same line in portable makefiles.

Escape dollar signs in recipes

Pass `$` through to the shell.

makefileANYportableshelldollar
makefile
print-pid:
  @echo $$PPID

Make uses `$` for variable expansion, so shell variables need `$$`.

Use tabs for recipe lines

Indent recipe commands with a tab character.

makefileANYportablesyntaxrecipes
makefile
target:
  printf 'hello
'

Traditional make syntax requires tabs unless you explicitly use GNU `.RECIPEPREFIX`.

Create directory safely

Ensure output directories exist.

makefileANYportabledirectories
makefile
build:
  mkdir -p build

`mkdir -p` is broadly available on modern POSIX systems.

Features to avoid for portability

Common GNU-only constructs that reduce portability.

Avoid eval for POSIX portability

Prefer explicit rules over GNU metaprogramming.

makefileANYportablegnu-only
makefile
# Prefer explicit rules when portability matters
app: main.o util.o
  $(CC) -o $@ $^

`eval`, `call`, `foreach`, and many text functions are GNU extensions.

Avoid GNU wildcard dependence

List sources explicitly or generate files in configure scripts.

makefileANYportablewildcard
makefile
SRC = main.c util.c api.c

Some highly portable makefiles avoid GNU-only discovery functions.

Avoid `.ONESHELL` when targeting POSIX make

Keep recipe-line semantics standard.

makefileANYportablegnu-onlyshell
makefile
release:
  cd dist && tar -czf app.tar.gz app

`.ONESHELL` is a GNU extension.

Recommended next

No recommendations yet.