Makefiles 101: Automating Your Workflow with `make`
Makefiles 101: Automating Your Workflow with make
Makefiles are a powerful but often overlooked tool for automating tasks in development workflows. Whether you're managing dependencies, running scripts, or cleaning up files, make
can simplify and streamline repetitive tasks.
Anatomy of a Makefile
A Makefile consists of targets, prerequisites, and recipes:
setup: deps.get yarn
$(run) mix ecto.reset
setup
: Target
- A file or directory that needs to be built.
deps.get yarn
: Prerequisites
- Other files or targets that must be completed before the target can be built.
$(run) mix ecto.reset
: Recipe
- A series of shell commands executed to build the target.
- Must be preceded by a tab, not spaces.
When we run make setup
, make
first ensures the prerequisites (deps.get
and yarn
) are built. Then, it executes the commands to build the setup
target.
make
will rebuild a target if it doesn’t exist or if any prerequisites have changed.
Phony Targets
A phony target is a target that doesn’t correspond to an actual file but instead serves as a label for a set of commands:
clean:
rm *.o temp
If a file named clean
ever appears in the directory, make
will assume it’s up to date and won’t execute the recipe. To avoid this issue, declare it as a phony target:
.PHONY: clean
clean:
rm *.o temp
Now, make clean
will always execute the cleanup commands.
Variables in Makefiles
Makefiles support different types of variable assignment:
foo = bar # Regular assignment
foo ?= wat # Assigns only if not already set
foo := boo # One-time immediate assignment
=
assigns a value but allows later changes.?=
assigns only if the variable hasn’t been set.:=
assigns immediately and won’t change later.
Passing Arguments to Make Targets
Make doesn’t support function-style arguments, but you can extract them from MAKECMDGOALS
:
args := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
add-migration:
bundle exec rails g migration $(args)
Now, you can pass arguments like:
make add-migration add_deleted_at_to_users deleted_at:datetime
However, this approach has limitations (e.g., limited argument count). If flexibility is needed, consider using shell scripts instead.
Makefile Cheatsheet
Command | Description |
---|---|
@ | Suppress printing the actual command, only show results |
Help Target
A common convention is adding a help target that greps comments to list available commands:
help:
@echo
@echo "Makefile targets:"
@grep -E '^[a-zA-Z_-].*?: .*?## .*$$' Makefile | sed 's#\\:#:#g' | awk 'BEGIN {FS = ": .*?## "}; {printf "\033[36m %-20s\033[0m %s\n", $$1, $$2}'
@echo
Usage:
make help
Example:
gql: ## Starts the GraphQL server
$(graphql)