make and makefile
I am a C/C++ newbie, but occassionally I have to compile or build projects. Since make (and Makefiles) are quite prevalent and sometimes they have to be adjusted due to potential errors, I had to learn more about them and want to share my learning publicly here.
Building Blocks
First of all, what are the involved building blocks of make and Makefiles?
- make:
- The GNU make utility. This is the executable that you actually run in order to execute a series of commands in order to modify files, typically compiling programs.
- If you run the program without specifying an explicit input file with the -f option, make will look for the makefiles GNUmakefile, makefile, and Makefile, in that order.
- make updates a target if it depends on prerequisite files that have been modified since the target was last modified, or if the target does not exist.
- makefile:
- This is the input file for the make utility and consists of a series of instructions how to modify files.
- A makefile can contain one or more rules.
- rule:
- A rule consists of one or more targets, prerequisites and commands.
- target:
- A target is a file name and typically, there is only one per rule.
- prerequisite:
- The prerequisites are file names, separated by spaces. These files need to exist before the commands for the target are run. These are also called dependencies.
- command:
- The commands are a series of steps typically to make the target. They need to start with a tab character, not spaces.
The general format of a Makefile is as follows:
| |
Example 1: Starting Simple
A more specific Makefile would be the following file:
| |
This file has one target named myfirsttarget, no prerequisites and only one command, which will execute the echo command:
| |
Typically, when a target is run (i.e., when the commands of a target are run), the commands will create a file with the same name as the target.
If we create a file named myfirsttarget in the same folder as the Makefile, the commands will no longer be executed:
| |
Example 2: Multiple Rules
Let us consider another example Makefile with two rules:
| |
The desired rule and target can be specified with make <targetname>.
If no target is specified, the first target of the Makefile is chosen automatically:
| |
Furthermore, multiple targets can be specified at once:
| |
The target execution can also be carried out in parallel with the -j option:
| |
Example 3: Variables
Variables can be used for dynamic input and they are limited to string values.
Single or double quotes have no meaning in make :
Variables can be declared either with = or :=, as shown below:
| |
They can be referenced either with ${var}, $(var), or $var:
| |
Example 4: Security Issues
Furthermore, a Makefile may be used for injection attacks, when a user is able to introduce malicious input in a variable.
Any variables are expanded before execution, regardless of any used quotes. Therefore, you should never allow unsanitized user input in the files:
Example Makefile:
| |
If an attacker is able to call make with the aforementioned Makefile and control the contents of the var variable, they can inject arbitrary commands, as demonstrated below:
| |
Similarly, the following Makefile will exhibit the same behaviour with single quotes:
| |
| |