Makefile学习之路4————让你的Makefile更专业
让你的makefile更专业。
在上一个Makefile所在目录下通过touch命令创建一个clean文件,然后执行make clean,将发现make总是提示clean文件是最新的,而不是按我们期望的那样对项目文件进行清楚操作。
make这样的行为,是因为它将clean当做文件来处理,在当前目录下找到了clean文件,而且clean目标没有任何先决条件,所以当我们要求make构建clean目标时它会认为clean文件是最新的,从而拒绝我们真正的文件清除操作。
出现这种情形,是因为我们对clean目标的定义与make所理解的有出入。目录文件名与makefile的目标名重名在现实项目中是难免的,假目标(phony target)概念的提出正是为了解决这种问题的。
假目标采用 .PHONY关键字来定义,注意必须是大写字母。运用假目标之后,更改makefile并运行如下:
.PHONY: clean app:main.o foo.o gcc -o app main.o foo.o main.o:main.c gcc -o main.o -c main.c foo.o:foo.c gcc -o foo.o -c foo.c clean: rm -rf app main.o foo.o
Linux下一切皆为文件。
采用.PHONY关键字声明一个目标之后,make并不会将其当做一个文件来处理。可以想象,由于假目标并不与文件关联,所以每次构建假目标时它所在规则中的命令一定会被执行。拿这里的clean目标做比方,即使多次执行make clean,make每次都会执行文件清楚操作。
运用变量提高可维护性:
编写专业的makefile离不开变量,通过使用变量可以使得makefile更具可维护性。
运用变量改写第一个makefiel。
.PHONY: clean CC = gcc RM = rm EXE =simple OBJS =main.o foo.o $(EXE): $(OBJS) $(CC) -o $(EXE) $(OBJS) main.o:main.c $(CC) -o main.o -c main.c foo.o:foo.c $(CC) -o foo.o -c foo.c clean: $(RM) -rf $(EXE) $(OBJS)
引入变量之后,如果需要更改编译器,只需要更改赋值变量的地方,其实相当于C语言宏定义的作用,便于更改移植。
上面的makefile,存在目标名和先决条件名在规则中重复出现,如果目标名或先决条件发生了改变,那么得在相应的命令中跟着更改这个很麻烦,为了省去这种麻烦,我们借助于如下一些自动变量:
除了这三个自动变量外,在makefile中还可以使用其他的自动变量,后面需要使用到的时候再提及。目前simple项目用这三个变量就足够了。
用上面的变量测试上面的Makefile。
.PHONY: all all:first second third @echo "\$$@ = $@" @echo "$$^ = $^" @echo "$$< = $<" first second third:
在Makefile中,“$”具有特殊的意思,如果想采用echo输出“$”,则必须用两个连着的“$”;
“$@” 对于Bash Shell 也有着特殊的意思,需要在“$$@”之前加一个反斜杠“\”(引号不包括在内)。
最后一行是一个只有目标的规则,如果除去它会有什么问题呢?读者可以自己试试。
注释(makefile中用#表示注释,需要注释多行,在注释行的末尾加上反斜杠"\",下一行也会被注释)最后一行之后报错如上图。显示没有规则创建上述目标。因为all的先决条件决定了构建all目标之前必须先构建first ,而first如果不存在,报错也是应该的。
采用自动变量之后运行结果的Makefile如下所示:
.PHONY: clean CC = gcc RM = rm EXE =simple OBJS =main.o foo.o $(EXE): $(OBJS) $(CC) -o $@ $^ main.o:main.c $(CC) -o $@ -c $^ foo.o:foo.c $(CC) -o $@ -c $^ clean: $(RM) -rf $(EXE) $(OBJS)
特殊变量:
在Makefile中,有两个特殊变量会经常用到:MAKE和MAKECMDGOALS。MAKE变量表示的是当前处理Makefile的命令名是什么。当需要在Makefile中运行另一个Makefile时,需要用到这个变量。
1 .PHONY: all 2 all: 3 @echo "MAKE = $(MAKE)"
MAKECMDGOALS变量表示的是当前构建的目标名。
1 .PHONY: all clean 2 all clean: 3 @echo "\$$@ = $@" 4 @echo "MAKECMDGOALS =$(MAKECMDGOALS)"
运行结果为:
从测试结果来看,MAKECMDGOALS变量指的是用户输入的目标,当只运行make命令且不带参数时,虽然根据Makefile的语法规则,Makefile中的第一个目标即为默认目标,即all目标,但MAKECMDGOALS在这里例外,MAKECMDGOALS此时是空而不是all目标,这一点需要注意。
运行make时可以同时指定多个目标。make在获得了多个目标后,将以从左到右的顺序逐个地构建目标。
CURDIR:是make的内嵌变量,指当前目录。
echo $(CURDIR)可以测试makefile的当前目录。
欢迎加入作者的小圈子
扫描下方左边二维码加入QQ交流群,扫描下方右边二维码关注个人微信公众号并,获取更多隐藏干货,QQ交流群:859800032 微信公众号:Crystal软件学堂
作者:Liu_Jing bilibili视频教程地址:https://space.bilibili.com/5782182 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在转载文章页面给出原文连接。 如果你觉得文章对你有所帮助,烦请点个推荐,你的支持是我更文的动力。 文中若有错误,请您务必指出,感谢给予我建议并让我提高的你。 |