When it comes to building C++ projects, there are various build systems available, each with its own advantages and disadvantages. One traditional and widely used build system is make
along with a Makefile
. In this blog post, we will explore the basics of a Makefile
and how it can be used as a C++ build system.
Table of Contents
- Introduction to Makefile
- The Makefile Structure
- Defining Targets and Prerequisites
- Using Variables in Makefile
- Compiling C++ Code with Makefile
- Cleaning Up with Phony Targets
- Conclusion
Introduction to Makefile
A Makefile
is a build configuration file that specifies how to compile and build a project. It contains rules, targets, dependencies, and actions to be executed. The make
tool reads the Makefile
and executes the necessary actions based on the file’s rules.
The Makefile Structure
A Makefile
consists of rules in the following format:
target: prerequisites
rules
- Target: The file or action to be built or executed.
- Prerequisites: The files or actions required to build the target.
- Rules: The actions to be executed when building the target.
Defining Targets and Prerequisites
Targets can be any file or action, such as compiling a C++ file or cleaning up generated files. Prerequisites are the files that the target depends on and must exist or be up to date before executing the rules.
For example, consider a simple Makefile
that compiles a C++ source file:
main: main.cpp
g++ -o main main.cpp
In this example, main
is the target, main.cpp
is the prerequisite, and the rule specifies how to compile main.cpp
using the g++
compiler.
Using Variables in Makefile
Variables in Makefile
can be used to store values and make the build rules more flexible. They are defined using the format variable_name = value
. To use a variable, prefix it with the $
symbol.
CXX = g++
CXXFLAGS = -std=c++17 -Wall
main: main.cpp
$(CXX) $(CXXFLAGS) -o main main.cpp
In this example, the CXX
variable stores the compiler (g++
), and CXXFLAGS
stores the compiler flags (-std=c++17 -Wall
). These variables are then used in the rule to compile the C++ file.
Compiling C++ Code with Makefile
To compile multiple files or when dependencies are involved, Makefile can become more complex. Let’s consider a scenario with multiple source files:
CXX = g++
CXXFLAGS = -std=c++17 -Wall
SOURCES = main.cpp foo.cpp bar.cpp
OBJECTS = $(SOURCES:.cpp=.o)
main: $(OBJECTS)
$(CXX) $(CXXFLAGS) -o main $(OBJECTS)
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
Here, we define the SOURCES
variable to include all the C++ source files. The OBJECTS
variable replaces the .cpp
extension with .o
to represent the object files. The target main
depends on all the object files and is built by compiling each object file individually using the %
wildcard rule.
Cleaning Up with Phony Targets
Phony targets are targets that do not represent actual files but perform an action. They are commonly used for cleaning up generated files or executing specific tasks.
.PHONY: clean
clean:
rm -f $(OBJECTS) main
In this example, a phony target clean
is defined to remove the object files and the compiled binary.
Conclusion
Using a Makefile
as a traditional C++ build system provides a flexible and customizable way to compile and manage C++ projects. It allows you to define targets, dependencies, and actions, making the build process more efficient and organized. With the knowledge gained from this blog post, you can start utilizing make
and Makefile
to improve your C++ development workflow.
#c++ #buildsystem