文章目录
1. 变量
1.1 自动变量
自动变量是Makefile中的一种特殊变量,它们在规则中的命令行被执行时自动设置。以下是一些常用的自动变量:
$@
:代表一个规则中的目标。当我们的一个规则中有多个目标时,它所指的是其中任何造成命令被运行的目标$^
:代表所有依赖文件,以空格分隔,不包含重复的依赖文件$<
:代表第一个依赖文件$?
:代表所有比目标更新的依赖文件,以空格分隔$*
:代表目标文件名中去掉后缀的部分
例如:
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
在这个例子中,$<
表示当前规则的第一个依赖文件(对应某个.c
文件),$@
表示当前规则的目标(对应某个.o
文件)。
1.2 特殊变量
特殊变量是Makefile中的预定义变量,它们具有特定的含义和功能。
MAKE
:表示的是 make 命令名是什么,当我们需要在 Makefile 中调用另一个 Makefile 时需要用到这个变量,采用这种方式,有利于写一个容易移植的 MakefileMAKEFILE_LIST
:已经包含的Makefile文件列表MAKECMDGOALS
:指的是用户输入的目标,当我们只运行 make 命令时,虽然根据 Makefile 的语法,第一个目标将成为缺省目标,即 all 目标,但 MAKECMDGOALS 仍然是空,而不是 all,这点需要注意
1.3 变量的类型
在Makefile中,变量可以分为两类:简单变量和递归变量。
- 简单变量:简单变量使用 := 进行赋值。它们在赋值时就会被展开
- 递归变量:递归变量使用 = 进行赋值。它们在使用时才会被展开
例如:
VAR1 = $(VAR2)
VAR2 := hello world
在这个例子中,VAR1 是一个递归变量,VAR2 是一个简单变量。
1.4 变量值的来源
变量的值可以来源于以下途径:
- 直接在Makefile中赋值
- 命令行参数传递
- 环境变量
1.5 高级变量的引用功能
在Makefile中,我们可以使用高级变量引用来更灵活地处理变量。例如:
$(VAR:str1=str2)
:在变量VAR的值中,将所有的str1替换为str2。
1.6 override指令
在Makefile中,我们可以使用override
指令来强制使用Makefile中的变量值,即使该变量已经在命令行中定义。例如:
CFLAGS = -Wall
override CFLAGS += -g
在这个例子中,我们使用了override
指令来确保CFLAGS
变量在Makefile中的定义被保留,而不是被命令行中的定义覆盖。即使在命令行中重新定义了CFLAGS
,Makefile中的CFLAGS
仍会被追加-g
选项。
1.7 总结
我们通过一个Makefile示例来展示上述讨论的各种变量类型和功能:
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
在这个Makefile中:
- 我们定义了简单变量
CC
、CFLAGS
和SRC
- 使用
override
指令确保CFLAGS
在Makefile中的定义不被命令行参数覆盖 - 使用高级变量引用
$(SRC:.c=.o)
将所有.c
文件转换为.o
文件列表 - 在目标
my_program
的命令行中,使用自动变量$@
代表当前目标(my_program),使用$^
代表所有依赖文件($(OBJS))。
2. 模式
Makefile 中的模式是一种简化书写 Makefile 的方法,它允许你为多个类似的目标定义通用规则。模式规则有一个或多个模式,通过使用通配符(%)表示。通配符可以匹配任意字符串。这使得我们可以为多个目标使用相同的规则,而不必为每个目标单独编写规则。
以下是一些常见的 Makefile 模式的例子:
-
编译 C 文件为目标文件(.o):
%.o: %.c gcc -c $< -o $@
这个模式表示:任何以
.o
结尾的文件(目标文件)都依赖于一个对应的以.c
结尾的文件(源文件)。规则中的命令行告诉编译器如何从源文件生成目标文件。$<
和$@
是自动变量,分别代表依赖文件和目标文件。 -
编译 C++ 文件为目标文件(.o):
%.o: %.cpp g++ -c $< -o $@
这个模式与上面的例子类似,只是它适用于 C++ 源文件。
-
将多个目标文件链接为一个可执行文件:
my_program: main.o helper.o gcc $^ -o $@ main.o: main.c gcc -c $< -o $@ helper.o: helper.c gcc -c $< -o $@
在这个例子中,我们没有使用模式,但我们可以用模式规则简化它:
my_program: main.o helper.o gcc $^ -o $@ %.o: %.c gcc -c $< -o $@
这个简化后的 Makefile 适用于所有 C 文件,而不仅仅是 main.c 和 helper.c。
-
在一个目录中生成 PDF 文件:
%.pdf: %.tex pdflatex $<
这个模式表示:任何以
.pdf
结尾的文件都依赖于一个对应的以.tex
结尾的文件。规则中的命令行告诉 pdflatex 如何从 LaTeX 源文件生成 PDF 文件。
3. 函数
Makefile 中的函数提供了一些实用的文本操作功能,可以让你更容易地处理文件名和路径。
3.1 addprefix
作用:给列表中的每个单词添加指定的前缀
语法:$(addprefix <prefix>, <list>)
示例:
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
作用:从列表中筛选出符合模式的单词
语法:$(filter <pattern>, <list>)
示例:
files = file1.txt file2.cpp file3.h file4.c
c_files = $(filter %.c, $(files))
# 结果:c_files = file4.c
3.3 filter-out
作用:从列表中移除符合模式的单词
语法:$(filter-out <pattern>, <list>)
示例:
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
作用:根据指定的模式替换列表中的单词
语法:$(patsubst <pattern>, <replacement>, <list>)
示例:
files = file1.txt file2.txt file3.txt
csv_files = $(patsubst %.txt, %.csv, $(files))
# 结果:csv_files = file1.csv file2.csv file3.csv
3.5 strip
作用:去除列表中的单词的前导和尾随空白字符
语法:$(strip <string>)
示例:
text = foo bar baz
stripped_text = $(strip $(text))
# 结果:stripped_text = foo bar baz
3.6 wildcard
作用:返回符合指定模式的文件列表
语法:$(wildcard <pattern>)
示例:
src_files = $(wildcard *.c)
# 结果:src_files = file1.c file2.c file3.c(假设目录中存在这些文件)