规则明确在什么情况下,使用什么方法,重构文件,该文件称为目标。
make的唯一目的是重构终极目标。终极目标默认是第一个目标。
1.
2.规则语法
TARGETS : PREREQUISITES
COMMAND
或者:
TARGETS : PREREQUISITES ; COMMAND
COMMAND
TARGETS 和 PREEQUISITES 可以是多对多的关系,但通常TARGETS 只代表单个目标。
每一行COMMAND(没有用;链接情况),make会fork一个进程去执行该命令,命令运行在shell系统之上。
规则的中心思想是: 目标文件的内容是由依赖文件文件决定, 依赖文件的任何一处改动,都将导致已经存在的目标文件过期。
$是特殊字符,代表变量或函数,$$表示$字符。
3.依赖类型
依赖类型分为普通类型和 order-only 类型。
普通类型依赖,当这种依赖文件被改动或新增,则认为目标文件已过期。
order-only类型依赖,这种依赖文件被改动,不会认为目标文件过期。
格式如下
TARGETS : NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES
示例
LIBS = libtest.a foo : foo.c | $(LIBS) $(CC) $(CFLAGS) $< -o $@ $(LIBS)
4.文件名使用通配符
可用的通配符有:*,[...],?
意义和shell的通配符相同。
make的通配符只能用在两个场景:
(1)目标和依赖处,make在解析阶段展开目标和依赖处的通配符
(2)规则处,在make执行阶段展开。
其他上下文不能使用通配符,只能用 函数 $(wildcard ) 实现。
5.目录搜索
(1)VPATH变量(一般性搜索)
make搜索文件时,现在当前目录搜索,若没有,则在VPATH指定的目录搜索。
定义VPATH,目录间用空格或冒号分隔
VPATH = src:../headers
通过VPATH指定的目录,对所有文件都有效,当需要为特定类型文件指定搜索路径时,应使用 vpath
(2)vpath关键字(选择性搜索)
vpath不是变量,而是关键字,path有3种使用方式
1、 vpath PATTERN DIRECTORIES 为所有符合模式“ PATTERN”的文件指定搜索目录“ DIRECTORIES”。多个目 录使用空格或者冒号(:)分开。类似上一小节的“ VPATH”变量。 2、 vpath PATTERN 清除之前为符合模式“ PATTERN”的文件设置的搜索路径。 3、 vpath 清除所有已被设置的文件搜索路径。
PATTERN 表示模式,其中可以使用%,%表示匹配一个或多个字符,如%.h表示所有以.h结尾的文件。如果PATTERN中没有包含%,那他就是明确的文件名。
vpath示例
vpath %.h ../headers
vpath %.c foo
vpath % blish
vpath %.c bar
表示对所有的.c 文件, make 依次查找目录:“ foo”、 blish”、“ bar”。
而:
vpath %.c foo: bar
vpath % blish
对于所有的.c 文件 make 将依次查找目录:“ foo”、“ bar”、“ blish”
(3)-INAME(依赖库)
-INAME 表示以目录搜索的方法添加依赖。
来看一下详细的过程。 1. make 在执行规则时会在当前目录下搜索一个名字为“ libNAME.so”的文件;
2. 如果当前工作目录下不存在这样一个文件,则make 会继续搜索使用“ VPATH”或者“ vpath”指定的搜索目录。
3. 还是不存在, make将搜索系统库文件存在的默认目录,顺序是:“ /lib”、“ /usr/lib”和“ /usr/local/lib”
如果“ libNAME.so”通过以上的途径最后还是没有找到的话,那么 make 将会按照以上的搜索顺序查找名字为“ libNAME.a”的文件。
可以这样使用:
假设你的系统中存在“ /usr/lib/libcurses.a”(不存在“ /usr/lib/libcurses.so”)这个 库文件。看一个例子: foo : foo.c -lcurses cc $^ -o $@
如果libcurses.a更新了,make就会认为 foo过期需要更新。
之所以 -INAME 会先寻找 libNAME.so ,若没找到再寻找 libNAME.a,是因为环境变量 .LIBPATTERNS
.LIBPATTERNS 默认值为 lib%.so lib%.a
6.伪目标
伪目标的目的:
(1)避免make的目标(只为了执行命令,不生成文件)和工作目录的文件重名。
(2)提高make的工作效率
当一个规则的目标为伪目标时,当运行到该规则时,规则的命令一定会被执行。
且make不会查找伪目标的隐含规则,意味提高了效率。
伪目标用于并行
SUBDIRS = foo bar baz subdirs: for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir; \ done
上面的make无法并行,因为只有一行,且$(MAKE)出错也不知道。
SUBDIRS = foo bar baz .PHONY: subdirs $(SUBDIRS) subdirs: $(SUBDIRS) $(SUBDIRS): $(MAKE) -C $@ foo: baz
如此就能多线程。
foo: baz 只是为了确定 foo 和 baz的执行顺序,所以无需命令。
7.强制目标
一个规则没有命令或依赖,并且他的目标不是存在的文件名。在执行此规则时,目标总被认为是最新的,即刚更新过。
将这个刚更新过的目标做其他目标的依赖,其他目标就一定会被更新。
clean: FORCE
rm $(objects)
FORCE:
强制目标和.PHONY效果一样,不过.PHONY更好。
8.
9.
10.
11.
12. 静态规则
语法
TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ...
COMMANDS
TAGET-PATTERN”和“ PREREQ-PATTERNS”说明了如何为每一个目标文件 生成依赖文件。从目标模式( TAGET-PATTERN)的目标名字中抽取一部分字符串(称 为“茎”)。使用“茎”替代依赖模式( PREREQ-PATTERNS)中的相应部分来产生对 应目标的依赖文件。下边详细介绍这一替代的过程。
示例
objects = foo.o bar.o all: $(objects) $(objects): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@
files = foo.elc bar.o lose.o $(filter %.o,$(files)): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ $(filter %.elc,$(files)): %.elc: %.el emacs -f batch-byte-compile $<
bigoutput littleoutput : %output : text.g generate text.g -$* > $@ 当执行此规则的命令时,自动环变量“ $*”被展开为“茎”。在这里就是“ big”和“ little”。
静态规则通常被其他makefile重复使用,
通常的做法是将生成同一类目标的模式定义在一个 make.rules 的文件中。在工程各个模块的 Makefile 中包含此文件。
13. 双冒号规则
Newprog :: foo.c $(CC) $(CFLAGS) $< -o $@ Newprog :: bar.c $(CC) $(CFLAGS) $< -o $@
当foo.c更新时,第一个规则的命令会被执行,当bar.c更新时,第二条规则的命令会被执行。
而如果使用单冒号,则会报错,必须将这两条规则合并,意味只能一种执行命令路线。