Makfile文件的命名规范
makefile的命名有两种方式:makefile和Makefile。
makefile的规则
规则的三要素:目标,依赖,命令。(完成makefile编写后在命令行进入其所在文件夹执行make命令即可执行makefile)
app:main.c add.c sub.c
gcc main.c add.c sub.c -o app
app 是项目的目标。
main.c add.c sub.c 为项目的依赖。
gcc main.c add.c sub.c -o app是makefile的编译命令, 要命令行前要有tab缩进。
改进:
app:main.o add.o sub.o mul.o
gcc main.o add.o sub.o mul.o -o app
main.o:main.c
gcc -c main.c
add.o:add.c
gcc -c add.c
mul.o:mul.c
gcc -c mul.c
sub.o:sub.c
gcc -c sub.c
改进版本的makefile在编译时只会重新编译被修改过的依赖。
makefile工作原理
makefile中的变量
使用变量对文件的重复字段进行替换,减少冗余。
obj=main.o add.o sub.o mul.o
target=app
$(target):$(obj)
gcc $(obj) -o $(target)
obj和target是自定义的变量,在完成定义后使用$()的形式对变量进行使用。
在使用了变量后,可以明显感觉到工作量的减少,但是仍需要编写大量相似的规则用来生成目标文件需要的依赖,下面就要考虑怎样对它进行替换,这就是makefile中的模式规则。
obj=main.o add.o sub.o mul.o
target=app
$(target):$(obj)
gcc $(obj) -o $(target)
%.o:%.c
gcc -c $< -o $@
目标文件的依赖如果不能直接找到将会执行下面的%.o:%.c的规则,它会将自己的依赖替换%。即app依赖main.o 它会执行执行%.o:%.c 产生main.c:main.o
$<和$@是makefile中的自动变量
$< :规则中的第一个依赖
$@ :规则中的目标
$^ :规则中的所有依赖
以上的三种自动变量只能使用在规则的命令中。
除了用户自定义的变量外,makefile还有一些自维护的变量,这些变量通常都是大写字母。例如CC默认值为cc,CPPFLAGS表示预处理需要的选项 -I ,CFLAGS是编译时使用的参数 -Wall -g -c ,LDFLAGS是链接库使用的选项 -L -l ;用户也可以根据需要修改这些变量的值。
makefile中的函数
makefile中函数使用实际上是使用函数的返回值
src=$(wildcard ./*.c)
在这行代码中,src是变量名用来接收函数的返回值;wildcard是函数名,其作用是将通配符展开(在使用wildcard的情况下,通配符在变量的定义和函数的引用时失效);wildcard后面的内容是参数(要被展开的内容),它要与函数名有一个空格。
使用wildcard可以获取文件中的所有.c结尾的文件,但在规则中往往还需要.o结尾的object文件,这将使用到另一个函数。
obj=$(patsubst ./%.c, ./%.o, $(src))
patsubst是makefile中的模式字符串替换函数,它会将src变量中的%.c替换为%.o,要注意第一个参数与函数名通过空格分隔,参数与参数通过‘,’,分隔。
makefile除了用来执行gcc命令,同意可以用来执行一些其他命令,以删文件为例
clean:
rm $(obj) $(target)
这条规则会删除变量obj和target中的文件。在这条规则中clean是规则的目标,rm是它的命令,这条规则没有依赖。
makefile在完成后使用命令行使用make命令执行,但是它只会生成终极目标(第一条规则),要执行后面的目标需要在make命令后加上目标名这个参数。
在使用clean这条规则时会发现一个现象,如果我们在当前文件夹中创建了一个名为clean的文件,那么在使用make clean命令时将会提示clean已经是最新的,这是有makefile的更新规则决定的,我们可以使用伪目标来对这条规则做出改进。
.PHONY:clean
clean:
rm $(obj) $(target) -f
.PHONY:clean就是声明clean为伪目标,这样clean将不会比较文件的更新。