1.Make的作用:
make的作用不在于指定哪个文件包含哪个之类,来说明怎样编译链接,这项工作由gcc或cc之类的编译器来完成。make的作用主要是根据文件之间的依赖关系,根据各自的更新时间,确定在编译的时候重新编译哪些,不用动哪些。同时使程序员在每次编译的时候不需要打这么多的命令。
2.特殊字符
%叫模式字符
#的意思是后面是注释
通配符有*(多字符) ?(单字符) []
$的意思是后面是函数或者变量
当真要用这些字符而不是取其特殊意思时,只有$是用$$,其他的都是在前面加反斜杠\
2.1 %和通配符的分别:
通配符用在规则的目标、依赖文件和命令中。但是在变量定义中不能用通配符,这时需要像wildcard的函数,函数中的模式也用的通配符。
模式字符能用来构建模式规则,而且只有第一个"%"字符有效。
一个模式规则的格式为: %.o:%.c ;COMMAND
(模式字符%至少匹配一个字符)
我的理解是,一般,当需要找出茎,进行替换动作的时候,用模式字符,当进行匹配动作的时候用通配符,例如:
$(patsubst %.c,%.o,$(wildcard *.c))
但是也有例外,vpath就用%。
3.自动化变量
使用自动化变量不仅是简单不易出错的原因,还有路径的原因。在命令中用自动化变量,自动化变量就被带有完整路径的文件名代替。
4.一个典型的规则样式是:
TARGET:PREREQUISITES
[tab]COMMAND
汉语就是:
目标:依赖文件
[tab键]命令
并不是包含了的头文件都要写到依赖文件中,依赖文件是为了决定有文件更新后是否重新生成目标,只有我们可能更新的文件才需要写到依赖文件中,库文件就不需要。
还要注意,生成中间目标例如kdb.o等时,cc的选项用-c,因为-c只编译不链接.
例子:
比较繁琐的规则:
main.o:main.c defs.h
cc -c main.c
考虑到隐含规则,可以简写成不带命令行: main.o:defs.h,只说明依赖关系就行了。
5.强制目标和伪目标
强制目标的规则里没有命令或者依赖。强制目标在规则的命令里没有生成目标的命令,所以每次都要执行,但是如果文件夹下有一个和目标同名的文件,就不一定每次都执行了。
而伪目标一旦被定义,不管存在不存在同名的文件,每次都会执行。这是伪目标的属性之一。
6.递归展开式变量和直接展开式变量
递归展开式变量使用"=",直接展开式变量使用":="。顾名思义,直接展开式变量就是从头走到这一句的时候,就展开":="后边的值赋给变量,以后再有什么变化也不影响变量的值了。递归展开式变量是直到这个变量在别的地方被调用的时候才展开后面的值。
例子:
START_TIME := $(shell date)
CURRENT_TIME = $(shell date)
START_TIME的值是固定的。CURRENT_TIME的值在每次需要的时候都重新运行一遍shell的date命令,取得当前时间。
7.其他小细节
7.1 测试字符串是否包含重复的字符:
# $(call has-duplicates, word-list)
has-duplicates = $(filter \
$(words $1) \
$(words $(sort $1)))
make函数并不了解数字,只了解字符串,因为我们必须把数字作为字符串来比较。最简单的方法就是使用filter函数。如果这两个数字相同,函数将返回一个非空值。
(make判断两个数是否相同的方法是用filter函数)
7.2 返回包含C源文件的每个子目录:
source-dirs := $(sort $(dir $(shell find . -name '*.c')))
从最内层开始看,find命令找出.c文件的完全路径,dir函数去掉函数名保留路径,sort去掉重复的并排序。
7.3 foreach函数。类似c语言的for循环

w依次等于$2里的值。要取w的值需要用$w的形式。
浙公网安备 33010602011771号