Makefile Builder

Generate a project Makefile with build, test, lint, and clean targets

Builds a Makefile with phony targets for build, test, lint, format, clean, and deploy, configurable variables, and a self-documenting help target that lists every command from its inline comments. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What does .PHONY do?

PHONY tells make a target is a command, not a file. Without it, a target named test would be skipped if a file called test existed, so all command targets are declared phony.

A clean Makefile without the tab traps

A good Makefile is the single entry point to a project: make test, make build, make deploy. But Make has sharp edges — recipes must start with real tabs, and command targets need .PHONY declarations. This builder generates a correct, self-documenting Makefile so newcomers can run make help and see everything available.

How it works

The output declares variables at the top so paths and binaries are set once. Every command target you enable is added to a .PHONY line and given a recipe that starts with a literal tab, as Make requires. Each target carries a ## description comment, and the help target uses a short grep/awk one-liner to print those descriptions, keeping documentation in sync with the targets. The first declared target is help, so running make with no arguments lists the commands instead of accidentally building.

The anatomy of a generated Makefile

A Makefile from this builder looks roughly like:

BIN := ./node_modules/.bin

.DEFAULT_GOAL := help

.PHONY: help build test lint clean

help:  ## Show this help message
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
	  | awk 'BEGIN {FS = ":.*?## "}; {printf "  %-12s %s\n", $$1, $$2}'

build:  ## Compile the project
	$(BIN)/tsc --project tsconfig.build.json

test:  ## Run the test suite
	$(BIN)/jest

lint:  ## Lint and type-check
	$(BIN)/eslint src && $(BIN)/tsc --noEmit

clean:  ## Remove build artifacts
	rm -rf dist

Every line inside a recipe begins with a real tab character, not spaces — this is a hard requirement of Make’s syntax. The builder emits correct tabs, so as long as you copy the output verbatim (and your editor does not convert tabs to spaces on paste), the Makefile will work.

Common pitfalls and how this builder avoids them

Tab vs space confusion

This is the most notorious Make trap. Make was written in 1976 and requires a literal ASCII tab (0x09) at the start of every recipe line. If your editor converts tabs to spaces or you retype a recipe, make throws Makefile:N: *** missing separator. Stop.. The builder emits correct tabs; copy the output as-is.

Missing .PHONY declarations

A target without .PHONY is treated as a filename. If a file named test or clean exists in the project root, make test silently does nothing because the “target” is already “up to date”. Declaring every command target as .PHONY prevents this, and the builder does it for you.

Default goal surprises

The first target in a Makefile is the default. If that target is build and you run a bare make expecting to see usage, you get a build instead. Setting help as the first target or setting .DEFAULT_GOAL := help gives every user a safe, informative default.

Tips and practical advice

  • Choose the Node preset to get npm run build, npm test, and npm run lint wired to the matching targets automatically.
  • Use variables at the top for paths: SRC := src, DIST := dist. Reference them in recipes with $(SRC) so refactoring means editing one line.
  • Add a watch target that invokes your build in watch mode for local development — pair it with ## Start dev watcher so it appears in make help.
  • For monorepos, a root Makefile can delegate to sub-packages: make -C packages/api test.

Run make help first to verify the output is correct, then run make build.