Article directory
1. Variables
1.1 Automatic variables
Automatic variables are special variables in Makefiles that are set automatically when the command line in the rule is executed. The following are some commonly used automatic variables:
$@
: Represents a target in a rule. When we have multiple targets in a rule, it refers to any of the targets that caused the command to be run$^
: Represents all dependent files, separated by spaces, does not contain duplicate dependent files$<
: represents the first dependent file$?
: Represents all dependent files newer than the target, separated by spaces$*
: Represents the part of the target file name that removes the suffix
For example:
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
In this example, $<
it represents the first dependent file of the current rule (corresponding to a certain .c
file), and $@
represents the target of the current rule (corresponding to a certain .o
file).
1.2 Special variables
Special variables are predefined variables in the Makefile that have specific meanings and functions.
MAKE
: Indicates what the make command name is. This variable needs to be used when we need to call another Makefile in the Makefile. This method is conducive to writing an easy-to-port MakefileMAKEFILE_LIST
: List of Makefiles already includedMAKECMDGOALS
: Refers to the target entered by the user. When we only run the make command, although according to the syntax of the Makefile, the first target will become the default target, that is, the all target, but MAKECMDGOALS is still empty instead of all. This requires Notice
1.3 Types of variables
In Makefile, variables can be divided into two categories: simple variables and recursive variables.
- Simple variables: Simple variables use := for assignment. They are expanded upon assignment
- Recursive variables: Recursive variables use = for assignment. They are only expanded when they are used
For example:
VAR1 = $(VAR2)
VAR2 := hello world
In this example, VAR1 is a recursive variable and VAR2 is a simple variable.
1.4 Sources of variable values
The value of a variable can come from the following ways:
- Assign directly in the Makefile
- command line parameter passing
- environment variable
1.5 Reference function of advanced variables
In Makefile, we can use advanced variable references to handle variables more flexibly. For example:
$(VAR:str1=str2)
: In the value of the variable VAR, replace all occurrences of str1 with str2.
1.6 override directive
In the Makefile, we can use override
directives to force the value of a variable in the Makefile even if the variable has been defined on the command line. For example:
CFLAGS = -Wall
override CFLAGS += -g
In this example, we use override
directives to ensure that CFLAGS
variables defined in the Makefile are preserved and not overwritten by definitions on the command line. CFLAGS
Options in the Makefile CFLAGS
are appended even if they are redefined on the command line -g
.
1.7 Summary
We use an example Makefile to demonstrate the various variable types and functions discussed above:
CC = gcc
CFLAGS = -Wall
override CFLAGS += -g
SRC = main.c foo.c bar.c
OBJS = $(SRC:.c=.o)
.PHONY: all clean
all: my_program
my_program: $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) my_program
In this Makefile:
- We define simple variables
CC
,CFLAGS
andSRC
- Use
override
directives to ensure thatCFLAGS
definitions in the Makefile are not overridden by command-line arguments $(SRC:.c=.o)
Convert all.c
files to.o
a list of files using advanced variable references- On the target
my_program
's command line, use automatic variables$@
for the current target (my_program) and for$^
all dependent files ($(OBJS)).
2. Mode
Patterns in Makefiles are a simplified way of writing Makefiles, allowing you to define common rules for multiple similar targets. Pattern rules have one or more patterns, expressed by using wildcard characters (%). Wildcards can match any string. This allows us to use the same rule for multiple targets without having to write a separate rule for each target.
Here are some examples of common Makefile patterns:
-
Compile C files as object files (.o):
%.o: %.c gcc -c $< -o $@
This pattern means that any
.o
file ending with _ (target file) depends on a corresponding.c
file ending with _(source file). The command lines in the rules tell the compiler how to generate object files from source files.$<
and$@
are automatic variables, representing dependent files and target files, respectively. -
Compile C++ files as object files (.o):
%.o: %.cpp g++ -c $< -o $@
This pattern is similar to the example above, except that it applies to C++ source files.
-
Link multiple object files into one executable:
my_program: main.o helper.o gcc $^ -o $@ main.o: main.c gcc -c $< -o $@ helper.o: helper.c gcc -c $< -o $@
In this example we didn't use patterns, but we can simplify it with pattern rules:
my_program: main.o helper.o gcc $^ -o $@ %.o: %.c gcc -c $< -o $@
This simplified Makefile applies to all C files, not just main.c and helper.c.
-
Generate PDF files in a directory:
%.pdf: %.tex pdflatex $<
This pattern means: any
.pdf
file ending in .depends on a corresponding.tex
file ending in . The command lines in the rules tell pdflatex how to generate PDF files from LaTeX source files.
3. Functions
Functions in Makefiles provide some useful text manipulation functions that allow you to deal with filenames and paths more easily.
3.1 addprefix
Function: Add the specified prefix to each word in the list
grammar:$(addprefix <prefix>, <list>)
Example:
files = file1.txt file2.txt file3.txt
prefixed_files = $(addprefix backup/, $(files))
# 结果:prefixed_files = backup/file1.txt backup/file2.txt backup/file3.txt
3.2 filter
Function: Filter out words that match the pattern from the list
grammar:$(filter <pattern>, <list>)
Example:
files = file1.txt file2.cpp file3.h file4.c
c_files = $(filter %.c, $(files))
# 结果:c_files = file4.c
3.3 filter-out
Function: Remove words that match the pattern from the list
grammar:$(filter-out <pattern>, <list>)
Example:
files = file1.txt file2.cpp file3.h file4.c
non_c_files = $(filter-out %.c, $(files))
# 结果:non_c_files = file1.txt file2.cpp file3.h
3.4 patsubst
Function: replace the words in the list according to the specified pattern
grammar:$(patsubst <pattern>, <replacement>, <list>)
Example:
files = file1.txt file2.txt file3.txt
csv_files = $(patsubst %.txt, %.csv, $(files))
# 结果:csv_files = file1.csv file2.csv file3.csv
3.5 strip
Function: Remove the leading and trailing whitespace characters of the words in the list
grammar:$(strip <string>)
Example:
text = foo bar baz
stripped_text = $(strip $(text))
# 结果:stripped_text = foo bar baz
3.6 wildcard
Function: Returns a list of files matching the specified pattern
grammar:$(wildcard <pattern>)
Example:
src_files = $(wildcard *.c)
# 结果:src_files = file1.c file2.c file3.c(假设目录中存在这些文件)