Make & Makefiles

make is a tool which you can use to build programs and run commands. It reads in Makefiles which are plaintext files which are commands which you want make to automate. Makefiles come in a variety of different formats and there is no ‘right’ way to write them. That being said, you are expected to know how to write the basic one, as outlined below.

Anatomy of a Makefile

# Comment

MACRO=VALUE

target: dependencies
	commands

Comments

Macros

Targets

Dependancies

Commands

Example

Using the following files we want to create a binary called animals in the bin directory.

.
├── Makefile
├── README
├── bin
├── include
│   ├── beavers.h
│   ├── cats.h
│   ├── kittens.h
│   ├── snakes.h
│   └── lizards.h
└── src
    ├── animals.c
    ├── beavers.c
    ├── cats.c (calls functions included in kittens)
    ├── kittens.c
    └── lizards.c (calls functions included in lizards)

Makefile 1: The Basic Makefile

In this example we just runs make in the same way that you would explicitly from the command prompt.

all: animals  # This line gets called when you just call make

animals:  # all calls this target in turn
	gcc -std=c99 -Wall src/beavers.c src/kittens.c src/lizards.c src/cats.c \
	src/animals.c -Iinclude -o bin/animals -lncurses  # split lines with '\'

Makefile 2: Separating Compilation and Linking

In this example we separate the compilation and linking steps. This is more efficient because compilation only occurs as-needed. This example also uses macros and includes a ‘clean’ target which removes all binary and object files.

CC=gcc
CFLAGS=-std=c99 -Wall
LDFLAGS=-lncurses
INCLUDES=-Iinclude
SRCDIR=src
BINDIR=bin

all: animals

animals: animals.o
	mkdir -p $(BINDIR)  # creates the bin directory if it doesn't already exist
	$(CC) animals.o beavers.o cats.o kittens.o lizards.o \
	-o $(BINDIR)/animals $(LDFLAGS)

animals.o: $(SRCDIR)/animals.c beavers.o cats.o kittens.o lizards.o
	$(CC) -c $(CFLAGS) $(SRCDIR)/animals.c $(INCLUDES)

beavers.o: $(SRCDIR)/beavers.c
	$(CC) -c $(CFLAGS) $(SRCDIR)/beavers.c $(INCLUDES)

cats.o: $(SRCDIR)/cats.c kittens.o  # since cats' functions call kittens'
	$(CC) -c $(CFLAGS) $(SRCDIR)/cats.c $(INCLUDES)

kittens.o: $(SRCDIR)/kittens.c
	$(CC) -c $(CFLAGS) $(SRCDIR)/kittens.c $(INCLUDES)

snakes.o: $(SRCDIR)/snakes.c lizards.o	
	$(CC) -c $(CFLAGS) $(SRCDIR)/snakes.c $(INCLUDES)

lizards.o:
	$(CC) -c $(CFLAGS) $(SRCDIR)/lizards.c $(INCLUDES)
	
clean:   # can be called using 'make clean'
	rm -r -f bin *.o *.dump