Essential Makefile Guide: Step-by-Step Project Compilation!

Linux | Red Hat Certified | IT Technology | Operations Engineer

👇1000 people technical exchange QQ group, note 【public number】 for faster access

Essential Makefile Guide: Step-by-Step Project Compilation!

1. Basic Structure of Makefile

The Makefile contains a series of “rules”, with the basic structure of each rule as follows:

target…: prerequisites… <tab> command

Target(target): usually the name of the file to be generated, or the name of the action to be performed, such as “clean”.

Prerequisites(prerequisites): the files or intermediate targets required to generate the target.

Command(command): commands executed to generate the target from the prerequisites. The command must start with a Tab character, not spaces.

Example (some items like $@, $^, .PHONY will be explained later).:

test:test.ccg++ -o $@ $^.PHONY:cleanclean:rm -f test

Note:

In Linux, .cpp is equivalent to .cc and .cxx

g++ is a compiler for C++ syntax, while gcc is a compiler for C syntax.

Before Use:

Essential Makefile Guide: Step-by-Step Project Compilation!

After using make, an executable file test is created:

Essential Makefile Guide: Step-by-Step Project Compilation!

After using make clean, the executable file test is deleted:

Essential Makefile Guide: Step-by-Step Project Compilation!

2. Working Principle of Makefile

Dependency Check: Before generating the target, make checks whether the dependencies in the rule exist. If not, it looks for rules to generate the missing dependency files.

Update Check: If the dependencies exist, make checks whether the timestamps of the dependencies are newer than the target’s timestamp. If the dependency’s timestamp is updated, it executes the command to update the target.

Command Execution: If the target needs updating, the commands in the rule are executed.

3. Common Commands and Options in Makefile

make command

Function: By default, it executes the first target in the Makefile.

Example:

Makefile:

test1:test1.ccg++ -o test1 test1.cctest2:test2.ccg++ -o test2 test2.cc

It executes g++ -o test1 test1.cc but will not execute g++ -o test2 test2.cc; if you want to execute both, it will be explained later.

Essential Makefile Guide: Step-by-Step Project Compilation!

Only the executable file test1 will be created, and test2 will not be created.

make clean

Function: Usually used to clean up intermediate files and the final generated target files during the compilation process.

make -f file

Function: Specifies a non-standard name for the Makefile, not using the default names: Makefile or makefile.

Example:

Assuming you have a Makefile named alt_makefile, you can use it with the following command:

make -f alt_makefile

When using the -f option, make will not look for Makefile, makefile, or GNUmakefile files in the current directory unless you explicitly specify them with -f.

You can specify multiple -f options to include multiple Makefile files. Make will read these files in the specified order and merge their rules. If the same rule is defined in multiple files, the later files will override the definitions from earlier files.

In some complex projects, there may be multiple Makefile files, each used for different build targets or environments. The -f option allows you to flexibly choose which Makefile file to use.

make -C dir

Function: Changes the working directory to dir before reading the Makefile.

Example:

Assuming your project structure is as follows, and you want to build the project in the src directory:

project/ ├── Makefile └── src/               ├── Makefile     └── ... (source files)

You can run the following command in the project root directory (project) to execute the Makefile in the src directory:

make -C src

make -n

Function: Prints the commands to be executed but does not execute them.

Example:

Essential Makefile Guide: Step-by-Step Project Compilation!

Only shows the execution content but does not execute, no executable file test is created.

make -s

Function: Executes the command but does not display the executed commands.

Example:

Essential Makefile Guide: Step-by-Step Project Compilation!

Does not display the execution content, but the command is executed, and the executable file test is created.

Essential Makefile Guide: Step-by-Step Project Compilation!

4. Variables in Makefile: $(VariableName) $@, $<, $^

Variables can be used in Makefile to simplify rule writing. Variables can be defined and used anywhere in the Makefile, and when referencing a variable, it must be in the form of $(VariableName).

Assignment: = and :=

When using = for assignment, Makefile performs lazy evaluation. This means the value of the variable is not immediately determined but recalculated based on the current value each time the variable is referenced.

When using := for assignment, Makefile performs immediate evaluation. This means the value of the variable is determined immediately at assignment and will not change thereafter (unless other mechanisms like the override directive are used).

$(VariableName)

Custom variable: For example, G=g++, defining a variable G with the value g++.

Example:

G=g++test:test.cc    $(G) -o test test.cc

Equivalent to

test:test.cc    g++ -o test test.cc

$@, $<, $^

Automatic variables: For example, $@ represents the target in the rule, $< represents the first prerequisite file, and $^ represents all prerequisite files.

Example 1:

test:test.cc    g++ -o $@ $^

Equivalent to:

test:test.cc    g++ -o test test.cc

Example 2:

test:test1.o test2.o test3.o    g++ -o $@ $^

Equivalent to

test:test1.o test2.o test3.o    g++ -o test test1.o test2.o test3.o

Example 3:

test:test.cc    g++ -o $@ $<

Equivalent to

test:test.cc    g++ -o test test.cc

5. Use of %

Pattern rules allow the use of % wildcard to match filenames, thus defining the same compilation rules for a group of files. For example:

CC=gcc%.o: %.c  $(CC) -c $< -o $@

This rule indicates that for all .c files, use $(CC) -c command to compile them into corresponding .o files.

6. Use of .PHONY

Phony targets are those that do not actually generate files, such as “clean”. To avoid conflicts with files of the same name, you can declare phony targets using .PHONY:

Cleaning example

Makefile code:

.PHONY: clean  clean:  rm -f $(shell find -name "*.o")

PHONY: clean: This line declares that clean is a phony target. This means that whenever you run make clean, make will execute the commands under the clean target without checking whether a file named clean exists or is up to date. This is particularly useful for commands that do not generate files (like cleanup commands).

clean: This is the start of the clean phony target. It is followed by the commands to be executed under that target.

rm -f $(shell find -name “*.o”): This is the command to be executed under the clean target. This command uses a combination of shell functions and the find command to search for and delete all files with the .o extension in the current directory and its subdirectories (usually object files generated during the compilation process).

$(shell find -name “*.o”): The shell function executes the command inside the parentheses in the shell before executing commands in the Makefile (in this case find -name “*.o”). This command searches the current directory and all its subdirectories for files ending with .o and returns their full paths. These paths are then received by the rm -f command for deletion.

rm -f: This command is used to delete files, and the -f option means “force”, which will not report an error even if the files do not exist.

Multiple different .cc files forming multiple different executable files example (taking two as an example)

Makefile code:

all:test1 test2test1:test1.ccg++ -o test1 test1.cctest2:test2.ccg++ -o test2 test2.ccclean:rm -f test1 test2.PHONY: all clean

Essential Makefile Guide: Step-by-Step Project Compilation!

7. Common Functions in Makefile: wildcard and patsubst

Makefile provides many built-in functions, such as wildcard, patsubst, etc., for matching, replacing file names, and other operations.

wildcard

$(wildcard pattern): Finds all files in the current directory that match the pattern.

For example:

SRC=$(wildcard *.cc)  

Finds all files with the .cc suffix in the current directory and assigns them to SRC. For example, if the current directory has main.cc and test.cc, then SRC=main.cc test.cc

Note: wildcard can only find files in the current directory. If the files you want to find are in a directory within the current directory, it cannot find them. In this case, you should use: SOURCES := $(shell find src -name “*.cc”)

patsubst

$(patsubst pattern,replacement,text): Replaces parts of text that match the pattern with replacement.

For example:

# Define a variable containing some filenames  FILES = foo.c bar.c baz.h    # Use patsubst to replace .c file extensions with .o  OBJECTS = $(patsubst %.c,%.o,$(FILES))  

8. Common Examples of Makefile

A test.cc file forms the corresponding test executable file

test:test.ccg++ -o $@ $^.PHONY:cleanclean:    rm -f test

Effect:

Input make to create the executable file test

Input make clean to delete the executable file test

Multiple .cc files forming corresponding executable files (taking two as an example)

all:test1 test2test1:test1.ccg++ -o test1 test1.cctest2:test2.ccg++ -o test2 test2.ccclean:rm -f test1 test2.PHONY: all clean

Essential Makefile Guide: Step-by-Step Project Compilation!

Course consultation add: HCIE666CCIE

↑ Or scan the QR code above ↑

What technical points and content do you want to see?

You can leave a message below to tell Xiaomeng!

Leave a Comment