Linux Makefile
2022-04-05 15:20 jym蒟蒻 阅读(138) 评论(0) 编辑 收藏 举报Makefile 格式
一个例子如下。Makefile由一系列规则组成。
规则格式如下:命令列表中的命令,以TAB键开始。
目标…: 依赖文件集合……
命令 1
命令 2
……
下面规则,目标是main,依赖文件是main.o input.o calcu.o,命令是gcc -o main main.o input.o calcu.o。
依赖文件其中任何一个更新了,目标也得更新。
更新,执行一遍规则中的命令列表。
由于第一次编译,main不存在,所以执行第一条规则。
由于第一条规则依赖于main.o input.o calcu.o,但是目前没有这三个.o文件,所以make会去找以这三个.o文件为目标的规则,然后执行。
main : main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
最后一个规则,目标是clean,但是没有依赖文件,所以其对应命令不执行。
如果想要执行clean,使用命令make clean。
make执行过程:
1.当前目录下,找以Makefile命名的文件。
2.找到后,按Makefile中的规则,编译生成最终的目标文件。
3.目标文件不存在,或目标的依赖文件比目标新,执行后面的命令更新目标。
Makefile中的变量都是字符串。
定义一个变量objects,使用=赋值。
引用变量使用$(变量名)。
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
变量的真实值,是它所引用的变量的最后一次有效值。
name = 111
curname = $(name)
name = 222
print:
@echo curname: $(curname)
运行结果如下。
不使用后定义的变量,只使用前面已经定义好的。
name = 111
curname := $(name)
name = 222
print:
@echo curname: $(curname)
运行结果如下。
如果变量在前面没有被赋值,那么就赋为新值;如果前面赋过值,那么就使用前面赋的值。
name = 111
curname = $(name)
curname ?= 222
print:
@echo curname: $(curname)
结果:
给前面已定义好的变量添加一些字符串。
objects = main.o inpiut.o
objects += calcu.o
通过模式规则,可以用一条规则,将所有.c 文件编译为对应的.o文件。
%表示长度任意的非空字符串。
如%.c,是所有以.c 结尾的文件。
a.%.c,表示以a.开头,以.c结束的所有文件。
下面这个代码加上命令,可以代替原来Makefile的3-8行代码。
命令还没写,需要借助自动化变量。
%.o : %.c
#命令
每一次对模式规则进行解析,都是不同的目标和依赖文件。
自动化变量,可以把符合模式的文件自动依次取出。
自动化变量,只出现在规则的命令中。
自动化变量 | 描述 |
---|---|
$@ | 规则中的目标集合,在模式规则中,如果有多个目标,$@表示匹配模式中定义的目标集合。 |
$< | 依赖文件集合中的第一个文件,如果依赖文件是以模式(%)定义的,$<是符合模式的一系列的文件集合。 |
$^ | 所有依赖文件的集合,空格分开,如果依赖文件中有多个重复的文件,$^会去除重复的依赖文件,只保留一份。 |
$% | 当目标是函数库时,表示规则中的目标成员名,如果目标不是函数库文件,那么其值为空。 |
$? | 所有比目标新的依赖目标集合,以空格分开。 |
$+ | 类似$^,但是,当依赖文件存在重复时,不会去除重复的依赖文件。 |
$* | 表示目标模式中%及其之前的部分,如果目标是test/a.test.c,目标模式为a.%.c,$*就是test/a.test。 |
下面这个代码,可以代替原来Makefile的3-8行代码。
%.o : %.c
gcc -c $<
下面这个代码,用来清理工程。
但是,规则中,没有创建文件clean的命令。
如果规则目录下创建一个名为clean的文件,执行make clean时,由于没有依赖文件,目标被认为是最新的。后面的rm命令不执行。
clean:
rm *.o
rm main
为解决这个问题,可以将clean声明成伪目标。
声明clean为伪目标后,无论当前目录下是否存在名为clean的文件,输入make clean,会执行rm命令。
.PHONY:clean
<条件关键字>
<条件为真时执行的语句>
endif
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
条件关键字:ifeq判断是否相等、ifneq判断是否不相等
ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’,‘ <参数 2>’
ifeq “<参数 1>”, “<参数 2>”
ifeq “<参数 1>”, ‘<参数 2>’
ifeq ‘<参数 1>’, “<参数 2>”
ifdef变量名非空,表达式为真、ifndef。
ifdef <变量名>
不支持自定义函数,函数是已经定义好的。
参数之间以逗号,隔开,函数名和参数之间用空格分开,调用函数以$开头。
$(函数名 参数集合)
${函数名 参数集合}
字符串替换。
$(subst <from>,<to>,<text>) 将字符串<text>中的<from>替换为<to>,返回替换以后的字符
串
$(subst jym,JYM,Dog is JYM)
模式字符串替换。
$(patsubst <pattern>,<replacement>,<text>)
找字符串<text>中,符合<pattern>的字符串,用<replacement>替换掉。
<pattern>可以使用通配符%表示任意长度的字符串。
$(patsubst %.c,%.o,a.c b.c c.c)
将字符串a.c b.c c.c中,所有符合%.c的字符串替换为%.o
替换后,字符串是a.o b.o c.o
获取目录。
$(dir <names…>)
从文件名序列<names>中提取出目录部分。
$(dir </src/a.c>)
提取文件/src/a.c的目录部分,/src。
去除文件中的目录部分,提取文件名。
$(notdir <names…>)
$(notdir </src/a.c>)
提取出a.c
完成循环。
$(foreach <var>, <list>,<text>)
把参数<list>中的单词逐一取出,放到参数<var>中。
执行<text>包含的表达式。
每次<text>都返回一个字符串。
循环的过程中,<text>中所包含的每个字符串以空格隔开。
最后整个循环结束时,<text>返回的每个字符串所组成的整个字符串是foreach函数的返回值。
names := a b c d
files := $(foreach n,$(names),$(n).o)
$(name)中的单词被挨个取出,存到变量n中。
$(n).o每次根据$(n)计算出一个值,这些值以空格分隔,最后作为foreach函数的返回
$(files)的值是“a.o b.o c.o d.o”。
%只有在规则中才会展开,变量定义和函数使用时,通配符不会自动展开,此时用函数wildcar。
$(wildcard PATTERN…)
$(wildcard *.c)
获取当前目录下,所有.c文件。