OOP-THU
OOP-THU copied to clipboard
Makefile的通配符与变量的使用
Makefile通配符与变量的使用
Makefile在我们上课时详细介绍,他为我们提供了“自动编译”的功能,只需要简短的命令,就能将整个工程文件重新编译,极大的降低了工程修改的成本,并提高了软件开发的效率。这里我们介绍一些Makefile的较高级用法。
Makefile的通配符
Makefile支持使用shell命令,因此在Makefile中可以直接使用shell所支持的一些通配符,如*
、%
、?
、[……]
等。
与正则表达式极其类似,其中,*
与%
表达匹配任意个字符,?
表示匹配任意一个字符,[……]
表示将指定需要匹配的内容放入[]
中。
例如:
test:*.cpp
g++ -o $@ $^
clean:
rm -rf *.o test
在以上代码中,我们看到,*
既可以用在规则中,也可以用在规则的命令中,此处即表示任意的以.c
pp或.o
结尾的文件。
需要特别指出的是,%
与*
作用极其类似,但%
将我们需要的所有文件组合成为一个列表,从列表中依次取出的每一个文件,%
即为取出文件的文件名。
例如:
test:*.o
g++ -o $@ $^
%.o:%.cpp
g++ -c $< -o $@
这段代码即表示依次取出%.cpp
文件。执行命令直至列表中文件为空。
这就是Makefile中的静态模规则:规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。
Makefile的变量
Makefile中定义变量的语法为:变量名称=值列表,等号左右对于空白符无要求,值列表可以是任意项,并且不需要使用数据类型。
在调用变量的时候可以使用$(VALUE_LIST)
或{VALUE_LIST}
。
而使用变量的优点在于,当我们需要添加或者是删除某个依赖文件的时候,我们只需要改变变量的值即可。
例如:
TEST = main.o test1.o test2.o test3.o
test:$(TEST)
g++ -o test $(TEST)
而变量赋值的基本方法有四种,分别是:
- 简单赋值 ( := ) :类比为
c++
中的普通赋值,只改变该变量。 - 递归赋值 ( = ) :类比为
c++
中的引用,赋值语句可能改变多个变量。 - 条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
- 追加赋值 ( += ) 将原变量用空格隔开的方式追加一个新值。
例如:
#简单赋值
a:=friend
b:=$(b)s
a:=guy
#递归赋值
c=friend
d=$(d)s
c=guy
#条件赋值
e:=friend
f:=$(e)s
e?=guy
#追加赋值
g:=friend
h:=$(g)s
g+=$(h)
#输出检验结果
test:
@echo "a=>$(a)"
@echo "b=>$(b)"
@echo "c=>$(c)"
@echo "d=>$(d)"
@echo "e=>$(e)"
@echo "f=>$(f)"
@echo "g=>$(g)"
@echo "h=>$(h)"
在命令行执行make test
,则有:
a=>friend
b=>friends
#在给b赋值的引用了变量a:$(a)
c=>guy
d=>guys
#随着c变化,采取递归赋值的d跟随变化
e=>friend
f=>friends
#e已经有值,因此条件赋值未生效
g=>friend
h=>friend friends
#在h=friend后追加空格以及变量g=friends
自动变量
在我们介绍通配符的时候,使用了符号$@
、$^
等,这些符号即为自动变量,它们具有很好的便捷性,如果能良好的使用,会极大地缩减我们的代码量。其中:
-
$@
表示目标文件的名称; -
$^
表示的是所有依赖文件的列表,使用空格进行分隔; -
$<
表示第一个依赖的文件名称; -
$?
表示所有比目标文件更新的依赖文件的列表,使用空格进行分隔; -
$%
表示静态库的一个成员名; -
$+
与$^
类似,但$^
只记录依赖文件第一次引用的情况,会去掉重复的依赖文件,而$+
会保留所有依赖文件中重复出现的文件,可以用于库的引用出现交叉时的情况。
让我们回到刚才的例子:
test:*.cpp
g++ -o $@ $^
clean:
rm -rf *.o test
其中$@
表示目标文件的名称,在此处被用作命名值,而$^
表示所有依赖文件,代表将所有文件统一链接。
test:*.o
g++ -o $@ $^
%.o:%.cpp
g++ -c $< -o $@
这段代码的test
指令与刚才相同,而第二个指令中,$^
表示依赖文件中的第一个,$@
代表目标文件,这个指令就是将所有的%.cpp
文件编译成为%.o
文件。
OK