A Makefile is a script that tells the make utility how to build and manage a project, typically by compiling source code into executables or libraries. You write rules that define targets (what to build), prerequisites (files needed), and recipes (commands to run), then run make to execute only the necessary steps. This article explains the core concepts with concrete examples, common pitfalls, and practical usage patterns.
Formula
The calculator above works out running pace and speed from finish time and distance. The formulas are:
- Average pace (min/km) = finish time (minutes) ÷ distance (km)
- Average speed (km/h) = distance (km) ÷ (finish time (minutes) ÷ 60)
Variables: t = finish time in minutes, d = distance in kilometers. Pace is expressed as minutes per kilometer, speed as kilometers per hour.
Worked Example
Using the default values: finish time = 50 minutes, distance = 10 km.
- Pace = 50 ÷ 10 = 5.00 min/km
- Speed = 10 ÷ (50 ÷ 60) = 10 ÷ 0.8333 = 12.00 km/h
The calculator shows 5.00 min/km and 12.00 km/h, matching the manual calculation.
Why Use a Makefile?
Makefiles automate repetitive build tasks. Instead of typing long compiler commands each time, you define them once. More importantly, make checks file timestamps: if a source file hasn’t changed since the last build, it skips recompiling that part. For large projects with hundreds of files, this saves significant time. Makefiles also handle dependencies—if a header changes, all files that include it get rebuilt automatically.
Basic Syntax and Structure
A makefile consists of rules with this shape:
target: prerequisites recipe
- Target: usually a file to generate (e.g.,
program) or a phony name likeclean. - Prerequisites: files that must exist before the target is built. If any prerequisite is newer than the target, the recipe runs.
- Recipe: shell commands, each line starting with a tab character (not spaces).
Example for a C program:
program: main.c utils.c gcc -o program main.c utils.c
If you run make program, make checks whether program exists and whether main.c or utils.c is newer. If so, it executes the gcc command.
Variables and Automatic Variables
Variables reduce repetition. Define them with NAME = value and use with $(NAME).
CC = gcc CFLAGS = -Wall -O2 program: main.c utils.c $(CC) $(CFLAGS) -o $@ $^
Here $@ is the target name (program), and $^ is all prerequisites (main.c utils.c). Other useful automatic variables:
$<– first prerequisite$?– prerequisites newer than target$*– stem of the target (for pattern rules)
Pattern rules use % as a wildcard. To compile any .c file into a .o file:
%.o: %.c $(CC) $(CFLAGS) -c $< -o $@
Phony Targets and Common Workflows
Targets like clean don’t correspond to files. If a file named clean exists, make would think it’s up to date and skip the recipe. Declare them as phony:
.PHONY: clean all all: program clean: rm -f *.o program
Now make clean always runs. A typical workflow includes all (default target), clean, install, and test. The first target in the makefile is the default when you run make with no arguments.
Common Mistakes and Troubleshooting
- Missing tab: Recipes must start with a tab, not spaces. Use
cat -e -t makefileto see tabs as^I. - Spaces in filenames: Escape them or use quotes. Better to avoid spaces in source file names.
- Incorrect dependencies: If you forget a header in prerequisites, make won’t rebuild when that header changes. Use
gcc -MMto generate dependency lists automatically. - Using
makewith directories: If a target is a directory, make may skip it. Use phony targets or.PHONYto avoid confusion. - Parallel builds:
make -j4runs four jobs simultaneously. Ensure your recipes don’t depend on each other in ways that break under parallelism.
Comparison with Other Build Tools
Make is the classic Unix tool, but modern alternatives exist:
- CMake: Generates makefiles (or Ninja files) from a higher-level description. Handles cross-platform builds and library detection.
- Ninja: Focuses on speed; designed for large projects with many files. Often used with CMake.
- Meson: Python-based, fast, and user-friendly, with built-in support for many languages.
- Bazel / Buck: Monorepo-scale build systems with advanced caching and remote execution.
Make is still widely used for small to medium projects, system administration, and as a generic task runner (e.g., for data pipelines). Its simplicity and ubiquity make it worth learning even if you later switch to a more specialized tool.
Advanced Techniques
- Conditionals: Use
ifeq,ifneq,ifdefto vary behavior by platform or configuration. - Functions:
$(wildcard *.c)lists all .c files,$(patsubst %.c,%.o,$(SRCS))converts a list. - Include files:
include other.mksplits makefiles into modules. - Automatic dependency generation: Use
gcc -MMDto create .d files that list header dependencies, then include them.
Example using wildcard and patsubst:
SRCS = $(wildcard *.c) OBJS = $(patsubst %.c,%.o,$(SRCS)) program: $(OBJS) gcc -o $@ $^
Frequently Asked Questions
What is the difference between = and := in a makefile?
= is recursive expansion: the variable is expanded every time it’s used, which can lead to infinite loops if not careful. := is simple expansion: the value is expanded once when defined. Use := for variables that reference other variables to avoid surprises.
Why does make say “Nothing to be done for ‘all’”?
This means the target all is up to date—none of its prerequisites have changed. If you expected a rebuild, check that the prerequisites are correctly listed and that file timestamps are actually newer. Sometimes cleaning first (make clean) forces a full rebuild.
How do I pass arguments to a make target?
You can pass variables on the command line: make target VAR=value. Inside the makefile, use $(VAR). Alternatively, use environment variables, but command-line assignments override them.
Can I use make for non-C projects?
Yes. Make is a general task runner. You can use it to run tests, deploy websites, process data, or any sequence of shell commands. The same rules apply: targets, prerequisites, and recipes.
How do I debug a makefile?
Run make -n to print commands without executing them. make -d gives detailed debugging output about what make is deciding. make -p prints the database of variables and rules. These help identify why a target isn’t being rebuilt.
What is a “phony” target and why do I need it?
A phony target is not a real file. Without declaring it .PHONY, make might skip it if a file with that name exists. Declaring it ensures the recipe always runs. Common phony targets are clean, all, and install.
Related
Formula used
in t | Finish time | min | 50 | 0 in d | Distance | km | 10 | 0 | 100000 out pace | Average pace | min/km | t / d | 2 out speed | Average speed | km/h | d / (t / 60) | 2
Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Jenkins vs GitHub Actions: Which CI/CD Fits Your Team?
- Turn Off Backup Encryption in iTunes?
- Campus Tech Innovation Hubs: What They Are
- Poco C51 Airtel Prepaid Locked Variant India?
- Shared VPS Hosting: Is It Better?
- Disk Defrag Pro: What It Does and Whether You Need It