Typing four gcc commands after every change is slow, and it is easy to forget one. make reads a file called Makefile that lists how each file is built, then runs only the commands that are needed.
A Makefile
CC = gcc
CFLAGS = -Wall -Wextra -std=c11 -g
app: main.o stack.o
$(CC) $(CFLAGS) -o app main.o stack.o
main.o: main.c stack.h
$(CC) $(CFLAGS) -c main.c
stack.o: stack.c stack.h
$(CC) $(CFLAGS) -c stack.c
clean:
rm -f app *.o
.PHONY: clean
Each rule has three parts:
- the target before the colon: the file this rule makes (
main.o); - the prerequisites after it: the files it is made from (
main.c stack.h); - the recipe on the next lines: the commands. Each recipe line must start with a Tab, not spaces. "missing separator" means spaces crept in.
CC and CFLAGS are variables; $(CFLAGS) is replaced by their value, so you change the flags in one place.
How make decides
Type make and it builds the first target, app. For each target it asks one question: is any prerequisite newer than the target? If yes (or the target does not exist yet), it runs the recipe. Before that, it does the same for each prerequisite, so the files are built in the right order.
#include <stdio.h>
/* A tiny make: rebuild a target only if something it needs is newer. */
struct file {
const char *name;
int time; /* when it last changed: bigger means newer */
};
struct file main_c = {"main.c", 5}, stack_c = {"stack.c", 9}, stack_h = {"stack.h", 2};
struct file main_o = {"main.o", 6}, stack_o = {"stack.o", 7}, app = {"app", 8};
int now = 10;
void build(struct file *target, struct file *a, struct file *b) {
if (a->time > target->time || b->time > target->time) {
printf("rebuild %s\n", target->name);
target->time = now++;
} else {
printf("%s is up to date\n", target->name);
}
}
int main(void) {
build(&main_o, &main_c, &stack_h);
build(&stack_o, &stack_c, &stack_h);
build(&app, &main_o, &stack_o);
return 0;
}This program does make's job for three rules. Each file has a time of its last change. stack.c (time 9) was edited after stack.o (time 7) was built, so stack.o is rebuilt. That makes it newer than app, so app is linked again. main.o is newer than both its prerequisites, so it is left alone.
Useful commands
| Command | What it does |
|---|---|
make | build the first target |
make stack.o | build one target |
make clean | run the clean rule: delete the built files |
make -n | show the commands without running them |
make -j4 | run up to 4 recipes at the same time |
.PHONY: clean tells make that clean is not a file, so it always runs. Bigger projects often use CMake, which writes the Makefile for you, but the idea is the same.
Quick check
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.