A makefile is a file that describes the relationship among the sources of a program used by the make utility to build (compile and link) the target goal (executable, shared object, and more). Makefiles are really important as they help to keep sources organized and easy to maintain. A program, to become executable, must be compiled and linked with other libraries. GCC is the most widely used collection of compilers. The two compilers used in the C and C++ world are GCC and g++ (for the C and C++ programs, respectively). This book will use g++.
Using a makefile to compile and link a program
How to do it...
This section will show how a makefile is written, to compile and run a simple C++ program. We'll develop a simple program, and create its makefile to learn its rules:
- Let's start by developing the program by opening the hello.cpp file:
$vi hello.cpp
- Type in the following code (refer to the Learning the Linux fundamentals - shell recipe to review the vi commands):
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}
- Save and exit: in vi, from the command mode, type :wq, which means write and quit. The :x command has the same effect.
- From the shell, create a new file called Makefile:
$ vi Makefile
- Type in the following code:
CC = g++
all: hello
hello: hello.o
${CC} -o hello hello.o
hello.o: hello.cpp
${CC} -c hello.cpp
clean:
rm hello.o hello
Although this is a typical Hello World! program, it is useful to show how a makefile is structured.
How it works...
Simply, a makefile consists of a set of rules. A rule consists of a target, a list of prerequisites, and a command.
In the first step, we opened the file (hello.cpp) and typed the program listed in step 2. Likewise, we opened another file, Makefile, in the same folder of the hello.cpp program, and typed the specific makefile commands. Let's now dive into the makefile internals. A typical makefile has the following content:
- The first rule consists of a target called all, and a prerequisite called hello. There is no command for this rule.
- The second rule consists of a target called hello. It has a prerequisite on hello.o and a command to link: g++.
- The third rule has a target called hello.o, a prerequisite on hello.cpp, and a command to compile: g++ -c hello.cpp.
- The last rule has a clean target with a command to remove all the hello and hello.o executables. This forces the recompilation of the files.
- For any rule, if any of the source files change, then the command defined is executed.
We're now able to compile the program using the makefile we created:
$ make
We're also able to execute the program, whose output is as follows:
The process of generating a binary executable from a source file includes the phase of compilation and linking, which here is compressed inside a single command; it'll be like this in most cases. In general, a large system code base relies on more sophisticated mechanisms but the steps are still the same: source file editing, compilation, and linking.
There's more...
This simple example just showed us the very basic concepts of a makefile and its make command. There is much more to it than that. Here are a few examples:
- Use of macros: A makefile allows the use of macros, which can be seen as variables. These can be used to organize the makefile to be more modular, for example:
- A macro for all the dynamic libraries used in the program: LIBS = -lxyz -labc.
- A macro for the compiler itself (in case you want to change to another compiler): COMPILER = GCC.
- Reference these macros over all the makefile: $(CC). This gives us the freedom to make changes in just one place.
- By just typing make on a shell, the first rule defined in the makefile will run. In our case, the first rule is all. If we changed the makefile by putting clean as a first rule, running make without parameters would execute the clean rule. In general, you'll always pass some parameters—for example, make clean.