EECS 280 Tutorials

make and Makefiles

The make utility automates compiling a program. It reads a file that’s usually called Makefile.

Prerequisites

This tutorial relies on command line tools. If you haven’t installed CLI tools on your machine yet, follow one of these tutorials first.

macOS Windows Linux

We’re also assuming you are familiar with a text editor or IDE. If you haven’t already done so, follow one of these tutorials.

VS Code (recommended) Visual Studio Xcode

Finally, you’ll need to be familiar with the command line interface (CLI). If you haven’t seen it yet, take a look at the Command Line Tutorial.

Example program

We’ll work in a directory called make-example just for this tutorial.

$ mkdir make-example

Create a file called main.cpp and copy-paste this Hello World program.

#include <iostream>
using namespace std;

int main() {
  cout << "Hello World!\n";
}

Create a file called Makefile and copy-paste this code.

CXX ?= g++
CXXFLAGS ?= -Wall -Werror -pedantic -g --std=c++17 -Wno-sign-compare -Wno-comment

# Run regression test
test: main.exe
	./main.exe < main_test.in > main_test.out
	diff main_test.out main_test.out.correct
	echo PASS

# Compile the main executable
main.exe: main.cpp
	$(CXX) $(CXXFLAGS) main.cpp -o main.exe

# Remove automatically generated files
clean :
	rm -rvf *.exe *~ *.out *.dSYM *.stackdump

Your directory should look like this:

$ tree
.
├── Makefile
└── main.cpp

Compile

Compile manually, then remove the executable.

$ g++ -Wall -Werror -pedantic -g --std=c++17 -Wno-sign-compare -Wno-comment main.cpp -o main.exe
$ ./main.exe
Hello World!
$ rm main.exe

Compile using make. Notice that it automated the long compile command.

$ make main.exe
g++ -Wall -Werror -pedantic -g --std=c++17 -Wno-sign-compare -Wno-comment main.cpp -o main.exe

Run the executable created by the previous make command.

$ ./main.exe
Hello World!

Clean up using make. Notice that it automated the rm command.

$ make clean
rm -rvf *.exe *~ *.out *.dSYM *.stackdump
removed 'main.exe'

Test

Makefiles are useful for automating tests, sometimes called a regression test.

Put input (stdin) in a file. We’ll use main_test.in in this example.

this program doesn't read stdin,
so this text doesn't matter

Put the correct output in a file. We’ll use main_test.out.correct. In EECS 280 and EECS 281, a few correct output files are typically provided.

Hello World!

Run manually with input redirection and output redirection. Compare with diff. No output means the files match.

$ ./main.exe < main_test.in > main_test.out
$ diff main_test.out main_test.out.correct

Run the regression test automatically with make.

$ make test
./main.exe < main_test.in > main_test.out
diff main_test.out main_test.out.correct

Pro-tip: Run commands in parallel with make -j.

$ make -j4 test

Makefile syntax

This section explains basic Makefile syntax.

A Makefile consists of rules that look like this:

target: prerequisites
	recipe

This is a concrete example of a rule.

main.exe: main.cpp
	g++ main.cpp -o main.exe

A target is usually the name of a file that is created by the rule, like main.exe.

A prerequisite is a file that is used as input to create the target, like main.cpp. There could be multiple prerequisites.

A recipe is a command that make runs, like g++ main.cpp -o main.exe. There might be more than one command.

Pitfall: Every recipe line must start with a TAB character.

A variable is helpful for avoiding duplication, like the compiler flags.

CXX ?= g++
# primer-spec-highlight-start
CXXFLAGS ?= -Wall -Werror -pedantic -g --std=c++17 -Wno-sign-compare -Wno-comment
# primer-spec-highlight-end

main.exe: main.cpp
# primer-spec-highlight-start
	$(CXX) $(CXXFLAGS) main.cpp -o main.exe
# primer-spec-highlight-end

unit_tests.exe: unit_tests.cpp unit.cpp
# primer-spec-highlight-start
	$(CXX) $(CXXFLAGS) unit_tests.cpp unit.cpp -o unit_tests.exe
# primer-spec-highlight-end

Acknowledgments

Original document written by Andrew DeOrio awdeorio@umich.edu.

This document is licensed under a Creative Commons Attribution-NonCommercial 4.0 License. You’re free to copy and share this document, but not to sell it. You may not share source code provided with this document.