Things I don’t keep in mind for long, so I write them down.

A Gentle Introduction to Makefiles

To make things easier, we can put the compilation commands into a script. That script is called a Makefile. This post is a quick note on writing a Makefile with a simple example.

Writing a Makefile

Suppose we have four files: main.cpp, hello.cpp, square.cpp, and utils.h. Their contents are as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//main.cpp
#include "utils.h"
#include <iostream>
using namespace std;

int main() {
hello();
cout << "The square of 5 is: " << square(5) << endl;
return 0;
}

//hello.cpp
#include "utils.h"
#include <iostream>
using namespace std;

void hello() {
cout << "Hello from hello()!" << endl;
}

//square.cpp
#include "utils.h"

int square(int n) {
return n * n;
}

//utils.h
#ifndef _UTILS_H_
#define _UTILS_H_

void hello();
int square(int n);

#endif

The final Makefile can look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CXX = g++
TARGET = main
SRC = $(wildcard *.cpp)
OBJ = $(patsubst %.cpp, %.o, $(SRC))

CXXFLAGS = -Wall

$(TARGET): $(OBJ)
$(CXX) -o $@ $^

%.o: %.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@

.PHONY: clean
clean:
rm -f *.o $(TARGET)

Now let’s look at how and why it is written this way.

The simplest approach is to turn the compilation command into a script. For our files, that command is g++ main.cpp hello.cpp square.cpp -o main, which creates an executable named main.

The Makefile would look like this:

1
2
main: main.cpp hello.cpp square.cpp
g++ main.cpp hello.cpp square.cpp -o main
A Gentle Introduction to Makefiles