A Makefile is a powerful script used by the make build automation tool to manage and streamline the compilation of projects, especially in languages like C++. In this lab, you’ll learn the fundamentals of creating a Makefile to automate the build process for a simple C++ project.
§1 Basic Structure of a Makefile #
A Makefile is composed of a set of rules. Each rule follows this structure:
target: dependencies
recipe
- target: The file or action the rule is intended to build or perform.
- dependencies: A list of files that the target depends on. The rule will only execute if the dependencies have been modified more recently than the target.
- recipe: A series of shell commands to be executed to build the target. Each command line in the recipe must be indented with a single tab character, not spaces.
§2 Basic Example #
For this lab, imagine a simple C++ project with the following file structure:
/project
main.cpp
utils.cpp
utils.h
Makefile
Our goal is to compile main.cpp and utils.cpp into a single executable file named my_program.
Here is a well-structured Makefile for this project:
1# Define the C++ compiler to use
2CXX = g++
3
4# Define compiler flags for warnings, C++ standard, and optimization
5CXXFLAGS = -Wall -Wextra -std=c++23 -O2
6
7# Define the name of the target executable
8TARGET = my_program
9
10# Automatically find all .cpp source files in the current directory
11SRCS = $(wildcard *.cpp)
12
13# Generate corresponding object file names by replacing .cpp with .o
14OBJS = $(SRCS:.cpp=.o)
15
16# The default rule, executed when you run `make` without arguments
17all: $(TARGET)
18
19# Rule to link the object files into the final executable
20$(TARGET): $(OBJS)
21 $(CXX) $(CXXFLAGS) -o $@ $^
22
23# Pattern rule to compile each .cpp source file into an object file
24%.o: %.cpp
25 $(CXX) $(CXXFLAGS) -c $< -o $@
26
27# Rule to clean up build artifacts
28clean:
29 rm -f $(OBJS) $(TARGET)
30
31# Declare targets that are not actual files
32.PHONY: all clean
§3 Explanation #
- Variables: We use variables like
CXX,CXXFLAGS,TARGET,SRCS, andOBJSto make the Makefile clean and easy to modify.CXX: The C++ compiler (e.g.,g++).CXXFLAGS: Flags passed to the compiler for warnings, optimization, etc.TARGET: The name of our final program.SRCS: A list of all.cppsource files, found automatically with$(wildcard *.cpp).OBJS: A list of object files (.o) that correspond to our source files.
- Default Target (
all): The first target in a Makefile is the default. Runningmakewill execute this target, which depends on our$(TARGET)executable. - Linking Rule: The rule
$(TARGET): $(OBJS)tellsmakehow to create the final executable by linking all the object files ($(OBJS)).$^is an automatic variable that represents all dependencies (the object files).$@is an automatic variable that represents the target name (the executable).
- Compilation Rule: The pattern rule
%.o: %.cppis a powerful feature that tellsmakehow to compile any.cppfile into its corresponding.oobject file.$<is an automatic variable that represents the first dependency (the source file).
- Clean Rule: The
cleantarget removes all compiled files, allowing you to rebuild the project from a clean state. - Phony Targets:
.PHONYtellsmakethatallandcleanare not actual files but commands to be executed. This prevents conflicts if a file namedcleanwere ever created.
make intelligently builds your project by following the dependency chain. When you ask it to build all, it sees that all depends on $(TARGET). Then, it sees that $(TARGET) depends on $(OBJS). Finally, it uses the pattern rule to compile any outdated source files into object files before linking them all together.
§4 Running the Makefile #
From your project’s root directory (where the Makefile is located), you can run the following commands:
To compile the project:
make
To run the compiled program:
./my_program
To clean up the build files:
make clean
§5 Further Reading #
For a comprehensive guide on make and Makefiles, this tutorial is an excellent resource: https://makefiletutorial.com
§6 Questions #
- In a
Makefile, what is the significance of using a tab character for indentation versus spaces?
- How would you modify the example Makefile to use the
clang++compiler instead ofg++?
- In the rule
%.o: %.cpp, what does the%symbol signify, and how does this rule help with building large projects containing many source files?
- How does make decide which targets need to be rebuilt?
- If you run
maketwice in a row without changing any source files, what happens during the second run and why?
- What is the purpose of the
cleantarget, and why is it essential to declare it as.PHONY?
- If you run
make, then modify only theutils.cppfile and runmakeagain, which specific files will be recompiled and relinked, and why?
- In the example Makefile, is there any difference between running
makeandmake all? Why or why not?
§7 Assignment #
Open the assignment link from the “Lab 2” Canvas page. Follow the directions in the README.md file.
Be sure to commit and sync your changes!
§7.1 Deliverables #
- A text submission or PDF containing answers to the Lab questions and a link to your
lab2code repository.