Structural and syntactical understand of a Makefile. What a target is and how it fits into a build pipeline. We use an example Makefile as a support throughout this tutorial.
Makefiles were introduced in 1976 by Stuart Feldman at Bell Labs. They are one of the oldest and most influential build automation tools in software development. Hence the following dino GIF.
Their purpose? Automate compiling and linking (especially for C projects), Makefiles let developers define rules for building targets from source files and dependencies, only rebuilding what’s necessary. Their quirky syntax (commands must be indented with a tab!) and flexible, shell-based approach made them a staple in Unix/Linux environments, powering everything from open-source projects and embedded systems to automation scripts for testing and deployment.
To solidify our understanding of Makefiles let’s walk through a concrete example. This is what a Makefile in the 1980s would look like
#!/usr/bin/make -f
# Makefile for a simple Java project with helpful dev commands
# author: Dennis Ritchie, Bell Labs
.PHONY: all build run test clean greeting
# Top-level alias for devs to just run everything
all: build run
# Build depends on compiling the Java files
build: Main.class
# The rule to compile Java source to class files
Main.class: Main.java Utils.java
javac Main.java Utils.java
# Run the app
run:
java Main
# Run unit tests
test:
java -cp .:junit-4.13.2.jar:hamcrest-core-1.3.jar org.junit.runner.JUnitCore MainTest
# Clean up generated files
clean:
rm -f *.class
example-hello:
echo "hello"
Seems scary? It’s not. Let’s start by clarifying some lingo you might find online: Target
In Makefiles, a target is the name before the colon (:
). It’s what you type after make
to run a group of commands. At the very bottom of the file notice we have a target called example-hello
. As you can see under it, the body of example-hello is echo "hello"
. When you run make example-hello
then you’ll see hello in your command line.
If all your target does is run commands, then it needs to be marked in the .PHONY
section at the top. This tells make
that it’s not a file you’re trying to create—it’s just a label for a set of instructions. So when we say:
.PHONY: all build run test clean greeting
We’re telling make
: “Hey, none of these are actual files—just do what I say when I call them.”
Dependencies: