# Build Systems
# Generating Build Environment with CMake
CMake (opens new window) generates build environments for nearly any compiler or IDE from a single project definition. The following examples will demonstrate how to add a CMake file to the cross-platform "Hello World" C++ code (opens new window).
CMake files are always named "CMakeLists.txt" and should already exist in every project's root directory (and possibly in sub-directories too.) A basic CMakeLists.txt file looks like:
cmake_minimum_required(VERSION 2.4) project(HelloWorld) add_executable(HelloWorld main.cpp)
This file tells CMake the project name, what file version to expect, and instructions to generate an executable called "HelloWorld" that requires
Generate a build environment for your installed compiler/IDE from the command line:
> cmake .
Build the application with:
> cmake --build .
This generates the default build environment for the system, depending on the OS and installed tools. Keep source code clean from any build artifacts with use of "out-of-source" builds:
> mkdir build > cd build > cmake .. > cmake --build .
CMake can also abstract the platform shell's basic commands from the previous example:
> cmake -E make_directory build > cmake -E chdir build cmake .. > cmake --build build
> cmake -G "NMake Makefiles" .. > nmake
# Compiling with GNU make
The GNU Make (styled
make) is a program dedicated to the automation of executing shell commands. GNU Make is one specific program that falls under the Make family. Make remains popular among Unix-like and POSIX-like operating systems, including those derived from the Linux kernel, Mac OS X, and BSD.
GNU Make is especially notable for being attached to the GNU Project, which is attached to the popular GNU/Linux operating system. GNU Make also has compatible versions running on various flavors of Windows and Mac OS X. It is also a very stable version with historical significance that remains popular. It is for these reasons that GNU Make is often taught alongside C and C++.
# Basic rules
To compile with make, create a Makefile in your project directory. Your Makefile could be as simple as:
# Set some variables to use in our command # First, we set the compiler to be g++ CXX=g++ # Then, we say that we want to compile with g++'s recommended warnings and some extra ones. CXXFLAGS=-Wall -Wextra -pedantic # This will be the output file EXE=app SRCS=main.cpp # When you call `make` at the command line, this "target" is called. # The $(EXE) at the right says that the `all` target depends on the `$(EXE)` target. # $(EXE) expands to be the content of the EXE variable # Note: Because this is the first target, it becomes the default target if `make` is called without target all: $(EXE) # This is equivalent to saying # app: $(SRCS) # $(SRCS) can be separated, which means that this target would depend on each file. # Note that this target has a "method body": the part indented by a tab (not four spaces). # When we build this target, make will execute the command, which is: # g++ -Wall -Wextra -pedantic -o app main.cpp # I.E. Compile main.cpp with warnings, and output to the file ./app $(EXE): $(SRCS) @$(CXX) $(CXXFLAGS) -o $@ $(SRCS) # This target should reverse the `all` target. If you call # make with an argument, like `make clean`, the corresponding target # gets called. clean: @rm -f $(EXE)
NOTE: Make absolutely sure that the indentations are with a tab, not with four spaces. Otherwise, you'll get an error of
Makefile:10: *** missing separator. Stop.
To run this from the command-line, do the following:
$ cd ~/Path/to/project $ make $ ls app main.cpp Makefile $ ./app Hello World! $ make clean $ ls main.cpp Makefile
# Incremental builds
When you start having more files, make becomes more useful. What if you edited a.cpp but not b.cpp? Recompiling b.cpp would take more time.
With the following directory structure:
. +-- src | +-- a.cpp | +-- a.hpp | +-- b.cpp | +-- b.hpp +-- Makefile
This would be a good Makefile:
CXX=g++ CXXFLAGS=-Wall -Wextra -pedantic EXE=app SRCS_GLOB=src/*.cpp SRCS=$(wildcard $(SRCS_GLOB)) OBJS=$(SRCS:.cpp=.o) all: $(EXE) $(EXE): $(OBJS) @$(CXX) -o $@ $(OBJS) depend: .depend .depend: $(SRCS) @-rm -f ./.depend @$(CXX) $(CXXFLAGS) -MM $^>>./.depend clean: -rm -f $(EXE) -rm $(OBJS) -rm *~ -rm .depend include .depend
Again watch the tabs. This new Makefile ensures that you only recompile changed files, minimizing compile time.
For more on make, see the official documentation by the Free Software Foundation (opens new window), the stackoverflow documentation (opens new window) and dmckee's elaborate answer on stackoverflow (opens new window).
# Building with SCons
You can build the cross-platform "Hello World" C++ code (opens new window), using Scons (opens new window) - A Python (opens new window)-language software construction tool.
First, create a file called
SConstruct (note that SCons will look for a file with this exact name by default). For now, the file should be in a directory right along your
hello.cpp. Write in the new file the line
Now, from the terminal, run
scons. You should see something like
$ scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... g++ -o hello.o -c hello.cpp g++ -o hello hello.o scons: done building targets.
(although the details will vary depending on your operating system and installed compiler).
Glob classes will help you further configure what to build. E.g., the
env=Environment(CPPPATH='/usr/include/boost/', CPPDEFINES=, LIBS=, SCONS_CXX_STANDARD="c++11" ) env.Program('hello', Glob('src/*.cpp'))
builds the executable
hello, using all
cpp files in
/usr/include/boost and it specifies the C++11 standard.
# Autotools (GNU)
The Autotools are a group of programs that create a GNU Build System for a given software package. It is a suite of tools that work together to produce various build resources, such as a Makefile (to be used with GNU Make). Thus, Autotools can be considered a de facto build system generator.
Some notable Autotools programs include:
- Automake (not to be confused with
In general, Autotools is meant to generate the Unix-compatible script and Makefile to allow the following command to build (as well as install) most packages (in the simple case):
./configure && make && make install
As such, Autotools also has a relationship with certain package managers, especially those that are attached to operating systems that conform to the POSIX Standard(s).
The Ninja build system is described by its project website as "a small build system with a focus on speed." (opens new window) Ninja is designed to have its files generated by build system file generators, and takes a low-level approach to build systems, in contrast to higher-level build system managers like CMake or Meson.
Ninja is primarily written in C++ and Python, and was created as an alternative to the SCons build system for the Chromium project.
# NMAKE (Microsoft Program Maintenance Utility)
NMAKE is a command-line utility developed by Microsoft to be used primarily in conjunction with Microsoft Visual Studio and/or the Visual C++ command line tools.
NMAKE is build system that falls under the Make family of build systems, but has certain distinct features that diverge from Unix-like Make programs, such as supporting Windows-specific file path syntax (which itself differs from Unix-style file paths).
Currently, there exists no universal or dominant build system for C++ that is both popular and cross-platform. However, there do exist several major build systems that are attached to major platforms/projects, the most notable being GNU Make with the GNU/Linux operating system and NMAKE with the Visual C++/Visual Studio project system.
Additionally, some Integrated Development Environments (IDEs) also include specialized build systems to be used specifically with the native IDE. Certain build system generators can generate these native IDE build system/project formats, such as CMake for Eclipse and Microsoft Visual Studio 2012.