Makefile编写规则(一)通配符和变量
Makefile 有自己的书写格式、关键字、函数。我们在本文中着重介绍一下Makefile的书写格式。如通配符,变量的定义,条件判断等等。
Makefile通配符
Makefile 是可以使用 shell 命令的,所以 shell 支持的通配符在 Makefile 中也是同样适用的。 shell 中使用的通配符有:"*","?","[...]"
1、* 匹配0个或者是任意个字符
2、? 匹配任意一个字符
3、[ ] 指定匹配的字符放在 "[]" 中
示例1
.PHONY:clean
clean:
rm -rf *.o test
这是在 Makefile 中经常使用的规则语句。这个实例可以说明通配符可以使用在规则的命令当中,表示的是任意的以 .o 结尾的文件。
示例2
test:*.c
gcc -o $@ $
这个实例可以说明我们的通配符不仅可以使用在规则的命令中,还可以使用在规则中。用来表示生所有的以 .c 结尾的文件。
但是如果我们的通配符使用在依赖的规则中的话一定要注意这个问题:不能通过引用变量的方式来使用,如下所示。
OBJ=*.c
test:$(OBJ)
gcc -o $@ $^
执行这个命令的时候会出现错误,提示我们没有 "*.c" 文件,实例中我们相要表示的是当前目录下所有的 ".c" 文件,但是我们在使用的时候并没有展开,而是直接识别成了一个文件。文件名是 "*.c"。
如果我们就是相要通过引用变量的话,我们要使用一个函数 "wildcard",这个函数在我们引用变量的时候,会帮我们展开。我们把上面的代码修改一下就可以使用了。
OBJ=$(wildcard *.c)
test:$(OBJ)
gcc -o $@ $^
我们再去使用的时候就可以了。调用函数的时候,会帮我们自动展开函数。
还有一个和通配符 "*" 相类似的字符,这个字符是 "%",也是匹配任意个字符,使用在我们的的规则当中
test:test.o test1.o gcc -o $@ $^ %.o:%.c gcc -o $@ $^
"%.o" 把我们需要的所有的 ".o" 文件组合成为一个列表,从列表中挨个取出的每一个文件,"%" 表示取出来文件的文件名(不包含后缀),然后找到文件中和 "%"名称相同的 ".c" 文件,然后执行下面的命令,直到列表中的文件全部被取出来为止。
这个属于 Makefile 中静态模规则:规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。跟我们的多规则目标的意思相近,但是又不相同。
Makefile变量的定义与使用
Makefile 文件中定义变量的基本语法如下:
变量的名称=值列表
变量的名称可以由大小写字母、阿拉伯数字和下划线构成。等号左右的空白符没有明确的要求,因为在执行 make 的时候多余的空白符会被自动的删除。至于值列表,既可以是零项,又可以是一项或者是多项。调用变量的时候可以用 "$(VALUE_LIST)" 或者是 "${VALUE_LIST}" 来替换,这就是变量的引用。实例:
OBJ=main.o test.o test1.o test2.o
test:$(OBJ)
gcc -o test $(OBJ)
变量的赋值
Makefile 的变量的四种基本赋值方式:
- 简单赋值 ( := ) 编程语言中常规理解的赋值方式,只对当前语句的变量有效。
- 递归赋值 ( = ) 赋值语句可能影响多个变量,所有目标变量相关的其他变量都受影响。
- 条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
- 追加赋值 ( += ) 原变量用空格隔开的方式追加一个新值。
(1)、简单赋值
x:=foo y:=$(x)b x:=new test: @echo "y=>$(y)" @echo "x=>$(x)"
(2)、递归赋值
x=foo y=$(x)b x=new test: @echo "y=>$(y)" @echo "x=>$(x)"
(3)、条件赋值
x:=foo y:=$(x)b x?=new test: @echo "y=>$(y)" @echo "x=>$(x)"
(4)、追加赋值
x:=foo y:=$(x)b x+=$(y) test: @echo "y=>$(y)" @echo "x=>$(x)"
变量使用的范围很广,它可以出现在规则的模式中,也可以出现在规则的命令中或者是作为 Makefile 函数的参数来使用。
Makefile自动化变量
自动化变量可以理解为由 Makefile 自动产生的变量,自动化变量的取值根据执行的规则来决定,取决于执行规则的目标文件和依赖文件。下面是对所有的自动化变量进行的说明:
自动化变量 | 说明 |
---|---|
$@ | 表示规则的目标文件名。如果目标是一个文档文件(Linux 中,一般成 .a 文件为文档文件,也成为静态的库文件), 那么它代表这个文档的文件名。在多目标模式规则中,它代表的是触发规则被执行的文件名。 |
$% | 当目标文件是一个静态库文件时,代表静态库的一个成员名。 |
$< | 规则的第一个依赖的文件名。如果是一个目标文件使用隐含的规则来重建,则它代表由隐含规则加入的第一个依赖文件。 |
$? | 所有比目标文件更新的依赖文件列表,空格分隔。如果目标文件时静态库文件,代表的是库文件(.o 文件)。 |
$^ | 代表的是所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的只能是所有的库成员(.o 文件)名。 一个文件可重复的出现在目标的依赖中,变量“$^”只记录它的第一次引用的情况。就是说变量“$^”会去掉重复的依赖文件。 |
$+ | 类似“$^”,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库的交叉引用场合。 |
$* | 在模式规则和静态模式规则中,代表“茎”。“茎”是目标模式中“%”所代表的部分(当文件名中存在目录时, “茎”也包含目录部分)。 |
实例1:
test:test.o test1.o test2.o gcc -o $@ $^ test.o:test.c test.h gcc -o $@ $< test1.o:test1.c test1.h gcc -o $@ $< test2.o:test2.c test2.h gcc -o $@ $<
这个规则模式中用到了 "$@" 、"$<" 和 "$^" 这三个自动化变量,对比之前写的 Makefile 中的命令,我们可以发现 "$@" 代表的是目标文件test,“$^”代表的是依赖的文件,“$<”代表的是依赖文件中的第一个。我们在执行 make 的时候,make 会自动识别命令中的自动化变量,并自动实现自动化变量中的值的替换。
实例2
lib:test.o test1.o test2.o
ar r $?
假如我们要做一个库文件,库文件的制作依赖于这三个文件。当修改了其中的某个依赖文件,在命令行执行 make 命令,库文件 "lib" 就会自动更新。"$?" 表示修改的文件。
make 中在这些变量中加入字符 "D" 或者 "F" 就形成了一系列变种的自动化变量,这些自动化变量可以对文件的名称进行操作。
变量名 | 功能 |
---|---|
$(@D) | 表示文件的目录部分(不包括斜杠)。如果 "$@" 表示的是 "dir/foo.o" 那么 "$(@D)" 表示的值就是 "dir"。如果 "$@" 不存在斜杠(文件在当前目录下),其值就是 "."。 |
$(@F) | 表示的是文件除目录外的部分(实际的文件名)。如果 "$@" 表示的是 "dir/foo.o",那么 "$@F" 表示的值为 "dir"。 |
$(*D) $(*F) |
分别代表 "茎" 中的目录部分和文件名部分 |
$(%D) $(%F) |
当以 "archive(member)" 形式静态库为目标时,分别表示库文件成员 "member" 名中的目录部分和文件名部分。踏进对这种新型时的目标有效。 |
$(<D) $(<F) |
表示第一个依赖文件的目录部分和文件名部分。 |
$(^D) $(^F) |
分别表示所有依赖文件的目录部分和文件部分。 |
$(+D) $(+F) |
分别表示所有的依赖文件的目录部分和文件部分。 |
$(?D) $(?F) |
分别表示更新的依赖文件的目录部分和文件名部分。 |