Makefile学习总结之Makefile的规则

Makefile的规则

foo.o:foo.c defs.h    #module for twidding the frobs 
cc -c -g foo.c

本例第一行中,文件“foo.o”是规则需要重建的文件,而“foo.c”和“defs.h”是重建“foo.h”所需要的文件。我们把规则所需要重建的文件称为规则的“目标”(foo.h)。而把重建目标所需要的文件称为规则的“依赖”。规则中的第二行“cc -c -g foo.c”是规则的“命令”。它描述了如何使用规则中的依赖文件重建目标。

  1. 规则的命令两种书写方式
    a) 命令可以和目标:依赖描述放在同一行。命令在依赖文件列表后并使用分号(;)和依赖文件列表分开;
    b) 命令在目标:依赖的描述的下一行,作为独立的命令行。当作为独立的命令行时此时必须以[Tab]字符开始。在Makefile中,在第一个规则之后出现的所有以[Tab]字符开始的行都会被当作命令来处理。
  2. Makefile中符号“$ ”由特殊的含义(表示变量或者函数的引用),在规则中需要使用“$ ”的地方,需要书写两个连续的(“$$”);
  3. 一个规则告诉make两件事:目标在什么情况下已经过期;如果需要重建目标时,如何去重建这个目标。目标是否过期是由那些使用空格分割的规则的依赖文件所决定的。当目标文件不存在或者目标文件的最后修改时间比依赖文件中的任何一个晚时,目标就会被创建或者重建。
  4. 执行规则命令行的前提条件是以下两者之一
    a) 目标文件不存在;
    b) 目标文件存在,但是规则的依赖文件中存在一个依赖的最后修改时间比目标的最后修改时间晚;
  5. 目标文件的内容是由依赖文件决定,依赖文件的任何一处改动,将导致目前已经存在的目标文件的内容过期。
  6. 对于A:B C这样的规则,在重建目标A之前,首先需要完成对它的依赖文件B和C的重建。重建B和C的过程就是执行Makefile中以文件B和C为目标的规则。其次,它确定了一个依存关系;规则中如果依赖文件中的任何一个目标文件新,则认为规则的目标已经过期而需要重建目标文件。通常,如果规则中依赖文件中的任何一个被更新,则规则的目标相应地也应该被更新。
  7. 更新依赖时,可不需要更新规则的目标。我们把这类称为“order-only”依赖。书写规则时,“order-only”依赖使用管道符号“|”开始,作为目标的一个依赖文件。规则依赖列表中管道符号“|”左边的常规依赖,管道右边的就是“order-only”依赖。书写的格式如下:
    TARGETS : NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES
    这样的规则中常规依赖文件可以是空;同样也可以对一个目标进行多次追加依赖。需要注意:规则依赖文件列表中如果一个文件同时出现在常规列表和“order-only”列表中,那么此文件被作为常规依赖处理。
  8. “order-only”依赖的使用举例:
LIBS = libtest.a
foo : foo.c | $(LIBS)
	  $(CC) $(CFLAGS) $< -o $@ $(LIBS)

make在执行这个规则时,如果目标文件“foo”已经存在,当foo.c被修改以后,目标foo将会被重建,但是当“libtest.a”被修改以后,将不执行规则的命令来重建目标“foo”。就是说,规则中依赖文件$(LIBS)只有在目标文件不存在的情况下,才会参与规则的执行。当目标文件存在时此依赖不会参与规则的执行过程。

  1. Makefile中表示文件名时可使用通配符。可用的通配符有:“* ”、“? ”和“[…]”。
  2. Makefile中通配符使用的场合:
    a) 可以用在规则的目标、依赖中,make在读取Makefile时会自动对其进行匹配处理;
    b) 可出现在规则的命令中,通配符的通配处理是在shell在执行命令时完成的;
  3. 如果规则的一个文件名包含统配字符(“* ”、“. ”等字符),在使用这样的文件时需要对文件名中的统配字符使用反斜线进行转义处理。例如“foo*bar”,在 Makefile中它表示了文件“foo*bar
  4. 以波浪线“~ ”开始的文件名有特殊含义。单独使用它或者其后跟一个斜线(~/),代表了当前用户的宿主目录(在 shell 下可以通过命令“echo ()”来查看)。例如“~/bin”代表“/home/username/bin/”(当前用户宿主目录下的 bin 目录)。波浪线之后跟一个单词(~ word),代表由这个“word”所指定的用户的宿主目录。例如“~john/bin”就是代表用户 john 的宿主目录下的 bin 目录。
print: *.c 
lpr -p $? 
touch print

上述的规则中目标“print”时一个空目标文件。(当前目录下存在一个文件“print”,但我们不关心它的实际内容,此文件的作用只是记录最后一次执行此规则的时间。自动环变量“$?”在这里表示依赖文件列表中被改变过的所有文件。

  1. 需要变量“objects”代表所有.o 文件列表示,需要使用函数“wildcard”
objects = $(wildcar *.o)
  1. 要使用函数“wildcard”,它的用法是:$(wildcard PATTERN…) 。在 Makefile 中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空。
  2. “ $(wildcard *.c)”来获取工作目录下的所有的.c 文件列表
  3. 使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c 文件列表;之后将列表中所有文件名的后缀.c 替换为.o。这样我们就可以得到在当前目录可生成的.o
vpath PATTERN DIRECTORIES

为所有符合模式“PATTERN”的文件指定搜索目录“DIRECTORIES”。多个目录使用空格或者冒号(:)分开。类似上一小节的“VPATH”变量。

vpath PATTERN

清除之前为符合模式“PATTERN”的文件设置的搜索路径。
21.

vpath

清除所有已被设置的文件搜索路径。
22. vpath使用方法中的“PATTERN”需要包含模式字符“%”。“%”意思是匹配一个或者多个字符,例如,“%.h”表示所有以“.h”结尾的文件。“DIRECTORIES”则指定了此类文件目录。当规则的依赖文件列表中的文件不能在当前目录下找到时,make程序将依次在“DIRECTORIES”所描述的目录下寻找此文件。

vpath %.h ../headers

其含义:Makefile中出现的.h文件;如果不能在当前目录下找到,则到“…/headers”下寻找。

  1. make在解析Makefile文件执行规则时对文件路径保存或废弃所依据的算法如下
    a) 如果规则的目标文件在makefile文件所在的目录下不存在,那么就执行目录搜寻;
    b) 如果目录搜寻成功,在指定的目录下存在此规则的目标。那么搜索到的完整的路径名就被作为临时的目标文件被保存;
    c) 对于规则中的所有依赖文件使用相同的方法处理;
    d) 完成第三步的依赖处理后,make程序就可以决定规则的目标是否需要重建,两种情况时后续处理如下:
    规则的目标不需要重建:那么通过目录搜素得到的所有完整的依赖文件路径名有效,同样,规则的目标文件的完整的路径名同样有效。
    规则的目标需要重建:那么通过目录搜素所得到的目标文件的完整路径名无效,规则中的目标文件将会被在工作目录下重建。
  2. Makefile的伪目标:它不代表一个真正的文件名,在执行make时可以指定这个目标来执行其所在规则定义的命令,有时也可以将一个伪目标称为标签。
  3. 将一个目标声明为伪目标的方法就是将它作为特殊目标.PHONY的依赖:
.PHONY : clean
  1. 伪目标的另外一种使用场合是在make的并行和递归执行过程中。
发布了39 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43443900/article/details/103372458