📄 gmake.txt
字号:
与"VPATH"变量相似但更具选择性的是"vpath"指令(注意是小写),可以指定对于符合特定模式文件的查找路径。这样可以为不同类型的文件指定不同的搜索路径。
"vpath"指令共有三中形式:
"vpath PATTERN DIRECTORIES" 为匹配PATTERN 的文件名指定搜索路径DIRECTORIES,目录的分隔和"VPATH"的相同
"vpath PATTERN" 清除为匹配PATTERN 的文件名指定的搜索路径
"vpath" 清除所有以前用"vpath"指定的搜索路径
"vpath"的模式是包含"%"的字符串:这个字符串必须匹配需要搜索的依赖文件名,"%"字符匹配0 个或多个任意字符。例如:"%.h"匹配任何以".h"结尾的文件(如果没有%,则PATTERN 必须和依赖文件完全一致,这种用法不太多)。
当前目录中不存在依赖文件时,如果"vpath"中的PATTERN 匹配依赖文件名,则指令中DIRECTORIES 列出的目录和"VPATH"中同样处理。举例:
vpath %.h ../headers
告诉make 在当前目录中未找到的".h"文件在../headers 目录中查找。如果多个"vapth"的模式匹配依赖文件名,make 将逐一处理,在所有指定的目录中搜索。Make 按照"vapth"在makefile 中的次序;来处理它们,多个相同模式的"vapth"是相互独立的。
vpath %.c foo
vpath % blish
vpath %.c bar
将按照"foo",‘blish","bar"的次序查找".c"文件。而
vpath %.c foo:bar
vpath % blish
按照"foo","bar","blish"的顺序搜索。
3.4.3 使用自动变量
目录搜索的结果并不改变规则中的命令:命令按原样被执行。因此,必须写出与目录搜索功相适应的命令。这可以通过使用"$^"这样的自动变量来完成。
"$^"表示规则中的所有依赖文件,包含它们所在的目录名(参见目录搜索);"$@"表示目标。例如:
foo.o : foo.c
cc -c $(CFLAGS) $^ -o $@
通常情况下,依赖文件也包含头文件,但命令中并不提及这些文件:
变量"$<"表示第一个依赖文件:
VPATH = src:../headers
foo.o : foo.c defs.h hack.h
cc -c $(CFLAGS) $< -o $@
3.4.4 目录搜索和隐含规则
使用"VPATH"和"vpath"指定目录搜索也会影响隐含规则。例如:文件"foo.o"没有显式规则,make 会考虑隐式规则:如果"foo.c"存在则编译它;如果这个文件不存在,则在相应的目录中查找;如果"foo.c"在任一的目录中存在,则C编译的隐式规则被应用。
隐式规则的命令使用自动变量通常是必要的,这样无需其它努力即可以使用目录搜索得到的文件名。
3.5 PHONY 目标
PHONY 目标并非实际的文件名:只是在显式请求时执行命令的名字。有两种理由需要使用PHONY 目标:避免和同名文件冲突,改善性能。
如果编写一个规则,并不产生目标文件,则其命令在每次make 该目标时都执行。
例如:
clean:
rm *.o temp
因为"rm"命令并不产生"clean"文件,则每次执行"make clean"的时候,该命令都会执行。如果目录中出现了"clean"文件,则规则失效了:没有依赖文件,文件"clean"始终是最新的,命令永远不会执行;为避免这个问题,可使用".PHONY"指明该目标。如:
.PHONY : clean
这样执行"make clean"会无视"clean"文件存在与否。
已知phony 目标并非是由其它文件生成的实际文件,make 会跳过隐含规则搜索。这就是声明phony 目标会改善性能的原因,即使你并不担心实际文件存在与否。
完整的例子如下:
.PHONY : clean
clean :
rm *.o temp
phony 目标不应是真正目标文件的依赖。如果这样,每次make 在更新此文件时,命令都会执行。只要phony 目标不是真正目标的依赖,规则的命令只有在指定此目标时才执行。
phony 目标可以有依赖关系。当一个目录中有多个程序,将其放在一个makefile 中会更方便。因为缺省目标是makefile 中的第一个目标,通常将这个phony 目标叫做"all",其依赖文件为各个程序:
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o utils.o
cc -o prog1 prog1.o utils.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o sort.o utils.o
cc -o prog3 prog3.o sort.o utils.o
这样,使用"make"将可以将三个程序都生成了。d
当一个phony 目标是另一个的依赖,其作用相当于子程序,例如:
.PHONY: cleanall cleanobj cleandiff
cleanall : cleanobj cleandiff
rm program
cleanobj :
rm *.o
cleandiff :
rm *.diff
3.6 FORCE 目标
当规则没有依赖关系也没有命令,而且其目标不是存在的文件名,make 认为此规则运行时这个目标总是被更新。这意味着如果规则依赖于此目标,其命令总是被执行。
clean: FORCE
rm $(objects)
FORCE:
例中目标"FORCE"满足这种特殊条件,这样依赖于它的目标"clean"被强制执行其命令。名字"FORCE"没有特殊含义,只不过通常这样用而已。这种方式使用"FORCE"和".PHONY : clean"效果相同。使用".PHONY"更加明确高效,但不是所有的"make"都支持;这样许多makefile 中使用了"FORCE"。
3.7 空目标
空目标(empty target)是phony 目标的变种:用来执行显式请求的一个动作。和phony 目标不同的是:这个目标文件可以真实存在,但文件的内容无关紧要,通常是空的。空目标文件的目的是利用其最后修改时间来记录命令最近一次执行的时间,这是通过使用"touch"命令更新目标文件来达到的。
print: foo.c bar.c
lpr -p $?
touch print
利用这条规则,执行"make print"时如果自上次"make print"之后任一文件改变了,"lpr"命令会执行。自动变量"$?"是为了只打印出那些变化了的文件。
3.8 内建的特殊目标
某些名字作为目标存在时有特殊含义。
★.PHONY 该目标的依赖被认为是phony 目标,处理这些目标时,命令无条件被执行,不管文件名是否存在及其最后修改时间
★.SUFFIXES 该目标的依赖被认为是一个后缀列表,在检查后缀规则时使用
★.DEFAULT 该目标的规则被使用在没有规则(显式的或隐含的)的目标上。如果"DEFAULT"命令定义了,则对所有不是规则目标的依赖文件都会执行该组命令
★.PRECIOUS 该目标的依赖文件会受到特别对待:如果make 被kill 或命令的执行被中止,这些目标并不删除;而且如果该目标是中间文件,在不需要时不会被删除。可以将隐含规则的目标模式(如%.o)做为".PRECIOUS"的依赖文件,这样可以保存这些规则产生的中间文件。
★.INTERMEDIATE 该目标的依赖文件被当作中间文件;如果该目标没有依赖文件,则makefile 中所有的目标文件均被认为是中间文件。
★.IGNORE 在执行该目标的依赖规则的命令时,make 会忽略错误,此规则本身的命令没有意义。如果该规则没有依赖关系,表示忽略所有命令执行的错误,这种用法只是为了向后兼容;由于会影响到所有的命令,所以不是特别有用,推荐使用其它更有选择性忽略错误的方法。
★.SILENT 在执行该目标的依赖规则的命令时,make 并不打印命令本身。该规则的命令没有意义。在".SILIENT"没有依赖关系时,表示执行makefile 中的所有命令都不会打印,该规则只是为了向后兼容提供的。
★.EXPORT_ALL_VARIABLES 只是作为一个目标存在,指示make 将所有变量输出到子进程中。
定义的隐含规则的后缀作为目标时,也认为它是特殊目标;两个后缀的连接也是一样,比如".c.o"。这些目标是后缀规则,一种定义隐式规则的过时方法(但仍然广泛使用)。后缀通常以"."开始,所以特殊目标也以"."开始。
3.9 一个规则多个目标
一条有多个目标的规则和写多条规则,每条一个目标作用是等同的。同样的命令应用于所有目标,但其效用会因将实际目标以"$@"代替而不同。规则中所有目标的依赖关系是一样的。这在两种情况下有用:
★只有依赖关系,不需要命令。例如:
kbd.o command.o files.o: command.h
★所有的目标同样的命令。命令不需要完全相同,因为在命令中可以使用"$@":
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@
和
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput
等同。这里假设程序"generate"产生两种输出:一种使用"-big"选项,一种使用"-little"选项。如果想象使用"$@"变化命令那样来变化依赖关系,不能通过多目标的普通规则实现,但是可以通过模式规则来实现。
3.10 一个目标多条规则
一个文件可以是多条规则的目标,所有规则的依赖关系被合并。如果目标比任一个依赖文件旧,命令被执行。一个文件只能有一组命令执行。如果多个规则对于同一个文件都给出了命令,make 使用最后一组并打印错误信息(特殊情况:如果文件名以"."开始,并不打印错误信息,这一点是为了和其它make 兼容)。没有任何理由需要将makefile写成这样,这是make 给出错误信息的理由。
一条只有依赖关系的附加规则可以一次给出许多文件的附加依赖文件。例如"objects"变量表示系统中编译器的所有输出,说明当"config.h"更改时所有文件必须重做的简单方法如下:
objects = foo.o bar.o
foo.o : defs.h
bar.o : defs.h test.h
$(objects) : config.h
不用改变实际目标文件生成的规则,这条规则可以在需要增删附加的依赖关系时插入或提出。另一个诀窍是附加的依赖关系可以用变量表示,在make 执行时,以给变量赋值:
extradeps=
$(objects) : $(extradeps)
当命令`make extradeps=foo.h'执行时会认为"foo.h"是每个目标文件的依赖文件,但简单的"make"命令不是这样。
3.11 静态模式规则
静态模式规则(static pattern rules)可以指定多个目标,并且使用目标名字来建议依赖文件的名字;比普通多目标规则更通用因为不需要依赖关系是相同的:依赖关系必须类似但不需要相同。
3.11.1 语法
TARGETS ...: TARGET-PATTERN: DEP-PATTERNS ...
COMMANDS
...
TARGETS 列表指出规则应用的目标,可以包含通配符,于普通规则的目标相同。
TARGET-PATTERN 和DEP-PATTERNS 来表明目标的依赖关系如何计算:匹配TARGET-PATTERN 的目标从名字中抽出一部分,叫做词干(stem),词干被替换到DEP-PATTERNS 来形成依赖文件名。
每个模式通常包含一个"%"字符。当TARGET-PATTERN 匹配一个目标时,"%"字符可以匹配目标名中的任何部分;这部分即是词干,模式的其余部分必须完全匹配。例如"foo.o"匹配"%.o","foo"是词干;目标"foo.c"和"foo.out"并不匹配这个模式。
目标的依赖文件名通过将DEP-PATTERNS 中的"%"替换为词干形成:如果依赖模式为"%.c",在替换词干"foo"可以得到"foo.c"。依赖模式中不包含"%"也是合法的,此依赖文件对所有的目标均有效。
如果需要在模式规则中使用"%"字符,必须在其前面加"\"字符,如果"%"前的"\"字符是有实际意义的,必须在其前面加"\",其它的"\"不必如此处理。如"the\%weird\\%pattern\\"在有效的"%"前是"the%weird\",其后是"pattern\\"。最后的"\\"保持原样是因为其并不影响"%"字符。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -