一、前言
由于这段时间公司的事情不多,也就是说,这段时间我可以将代码的学习作为主要任务,公司像自习室,这虽然听起来很美好,仿佛又回到了无忧无虑的大学生活,但是,这段时间也是最容易松懈的,真正的“代码战士”是不能休息的,即使是春节等重大节日!因此,在工作不忙的时候,我会坚持日更,我不会舍弃文章的质量,而是文中所写都是经过我思考后的尽可能浓缩的知识点。真心推荐大家去看看《跟我一起写 Makefile》--陈皓_Sudley的博客-CSDN博客。
在我第一次学习大型工程的Makefile的时候,给我的第一印象就是看天书,我知道Makefile的基本形式和工作方式,但是只了解这些是远远不够的。我总结了三点让Makefile晦涩难懂的原因:
1)变量定义
2)函数
3)隐式规则
接下来,我将对这三部分进行总结归纳,希望看过这篇文章可以帮助大家更快上手大型工程的Makefile,并对整个工程有更深入的理解。由于函数的篇幅可能过长,在这里我之总结一下变量的知识点和使用技巧。在接下来的两篇学习笔记中,我将分别介绍函数和隐式规则这两部分。
Makefile基本形式:
target :prerequisites
(Tab)command
target:目标文件、可执行文件以及标签
prerequisites:生成target所需的文件
command:需要执行的命令
注:(Tab)不要忘记哦!
二、变量定义
2.1 变量基础
变量的定义很想c语言中的赋值,例如:
obj = test.o
这里需要注意的点是,如何引用变量。我们可以写一个简单的Makefile文件,如下:
obj = test.o
all:
@echo obj
@echo $(obj)
执行make all后,结果如下:
obj
test.o
我想大家应该知道两者的区别了,这也是Makefile变量定义和c语言变量定义的区别。
2.2 变量的意义
我觉得变量的意义在于简化代码,让代码的可读性更高。我总结了三个变量适用范围,如下:
1)表示目标文件,依赖文件以及命令的部分;
prog = test
obj = test.o
gcc = CC
$(prog):$(obj)
$(CC) -o $(prog) $(obj)
$(obj): test.c
$(CC) -c test.c
2)表示文件路径;
哈哈,这就不用举例了:)
3)表示具有相同文件的多个同类型文件。
IDUS = IDU1 IDU2 IDU3
ICD = $(addsuffix -icd.xlsx,$(addprefix ./Generated/,$(IDUS)))
all:
@echo $(ICD)
这里面addsuffix和addprefix分别是后缀和前缀的意思。
结果如下:
./Generated/IDU1-icd.xlsx ./Generated/IDU2-icd.xlsx ./Generated/IDU3-icd.xlsx
2.3 变量的实用用法
(var:a =b)是一个非常实用的技巧,它的意思是将var中的a变为b,这样我们可以批量的改变文件的命名或者类型,例子如下:
obj = a.o b.o c.o
src = $(obj:.o=.c)
all:
@echo $(obj)
@echo $(src)
执行make all后,结果如下:
a.o b.o c.o
a.c b.c c.c
注: src = $(obj:.o=.c)中":"和".o"之间是不能有空格的!
2.4 追加变量值
obj=a.o b.o c.o
obj+=d.o
等价于
obj:=$(obj) d.o
其中,":="可以避免赋值迭代。
2.5 目标变量
目标变量,我们可以把目标变量理解为“定义在某一个目标以及该目标引发的所有规则中的变量”,类似局部变量。这部分很关键,因为根据我的经验,目标变量是很多时候看不懂Makefile的罪魁祸首。因为,大型工程的Makefile往往很长,在阅读时很可能找不全一个目标的全部规则,这种情况一旦发生基本就读不懂代码的细节了。
我直接引用陈皓在《跟我一起写Makefile》中的例子。
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o
prog.o : prog.c
$(CC) $(CFLAGS) prog.c
foo.o : foo.c
$(CC) $(CFLAGS) foo.c
bar.o : bar.c
$(CC) $(CFLAGS) bar.c
三、结语
希望大家提出宝贵的意见:)