tanxiaohai ######################################################################## 二、make通过比较对应文件(规则的目标和依赖)的最后修改时间,来决定哪些文件需要更新、哪些文件不需要更新。对需要更新的文件make就执行数据库中所记录的相应命令来重建它,对于不需要重建的文件make什么也不做。 三、make会重编译的情况: 1.所有源文件没有被编译过,则对各个C源文件进行编译并进行链接,生成最后的可执行程序; 2.每一个在上次执行make之后修改过的C源代码文件在本次执行make时将会被重新编译; 3.头文件在上一次执行make之后被修改。所有包含此头文件的C源文件都会被重新编译; --------------》》》》》》》》Makefile target: #目标 clean: #伪目标 prerequisites: #规则的依赖 command: #规则的命令行,必须Tab开头(shell命令或可执行程序) " \ "可将较长行分解成多行,注:\后不可有空格 只有执行动作,没有依赖的目标都称为"伪目标"。 四、make的第一个规则的第一个目标为最终目标 即Makefile最终需要更新或者创建的目标 终极目标一般用 all: 表示 五、Makefile中常用的变量 RM := -rf CXXFLAGS #g++/gcc 的编译选项列表 CPP_SRCS #c++的源程序列表 OBJS #编译的(".o" )目标列表 LIBS #链接库列表 六、.PHONY:clean 将clean目标声明为伪目标,即将后的目标列表都声明为伪目标 七、Makefile主要包含5个内容:显示规则、隐含规则、变量定义、指示符、注释 # 可以实现注释本行后面的内容,如果行尾有“\”时将下一行也注释, \# 为对特殊字符"#"的转义,此时无注释功能。 八、第一个规则之后所有以[Tab]开头的行都会被交给系统shell程序去解析执行。 九、执行make时按照文件名顺序读取文件并执行:“GNUmakefile”、“makefile”、”Makefile“ 第一个只有GNU make才能识别 十、通过命令指定目标使用make的隐含规则: 1.有file.c或file.cpp时, 使用make file.o 会执行 gcc/g++ -o file.o file.c/file.cpp 十一、可执行文件的格式为“ELF”格式 ######################################################################### 十二、“include”指示符告诉make暂停读取当前的Makefile,而转去读取“include”指定的一个或者多个文件,完成以后再继续当前Makefile的读取。Makefile中指示符“include”书写在独立的一行 1. 有多个不同的程序,由不同目录下的几个独立的Makefile来描述其重建规则。 2. 当根据源文件自动产生依赖文件时;我们可以将自动产生的依赖关系保存在另外一个文件中 如果指示符“include”指定的文件不是以斜线开始(绝对路径,如/usr/src/Makefile...),而且当前目录下也不存在此文件;make将根据文件名试图在以下几个目录下查找 -include FILENAMES... 使用这种方式时,当所要包含的文件不存在时不会有错误提示、make也不会退出;除此之外,和第一种方式效果相同 为了和其它的make程序进行兼容。也可以使用“sinclude”来代替“-include”(GNU所支持的方式)。 十三、如果在当前环境定义了一个“MAKEFILES”环境变量,make执行时首先将此变量的值作为需要读入的Makefile文件,多个文件之间使用空格分开。 十四、make程序在读取多个makefile文件时,包括由环境变量“MAKEFILES”指定、命令行指、当前工作下的默认的以及使用指示符“include”指定包含的,在对这些文件进行解析执行之前make读取的文件名将会被自动依次追加到变量“MAKEFILE_LIST”的定义域中。 十五、特殊变量 一个重要的特殊的变量是“.VARIABLES”。它被展开以后是此引用点之前、makefile文件中所定义的所有全局变量列表。包括:空变量(未赋值的变量)和make的内嵌变量 十六、makefile文件的重建??????????????????????? ######################################################################## 十七、make 如何解析Makefile文件 第一阶段:读取所有的makefile文件(包括“MAKIFILES”变量指定的、指示符“include”指定的、以及命令行选项“-f(--file)”指定的makefile文件),内建所有的变量、明确规则和隐含规则,并建立所有目标和依赖之间的依赖关系结构链表。 第二阶段:根据第一阶段已经建立的依赖关系结构链表决定哪些目标需要更新,并使用对应的规则来重建这些目标。 *************************************************************************************************************** 第四章:Makefile的规则 ************************************************************************************************************** 1、除了makefile的“终极目标”所在的规则以外,其它规则的顺序在makefile文件中没有意义 2、多个目标中的第一个将会被作为make的“终极目标”。 有两种情况的例外: (1) 目标名以点号“.”开始的并且其后不存在斜线“/”(“./”被认为是当前目录;“../”被认为是上一级目录); (2) 模式规则的目标。当这两种目标所在的规则是Makefile的第一个规则时,它们并不会被作为“终极目标”。 3.有时,需要定义一个这样的规则,在更新目标(目标文件已经存在)时只需要根据依赖文件中的部分来决定目标是否需要被重建,而不是在依赖文件的任何一个被修改后都重建目标。 规则依赖列表中管道符号“|”左边的是常规依赖,管道符号右边的就是“order-only”依赖及修改后目标不需重建。 4.Maekfile中表示文件名时可使用通配符。可使用的通配符有:“*”、“?”和“[…]”。不过只可以出现在下面两个地方。 (1). 可以用在规则的目标、依赖中,make在读取Makefile时会自动对其进行匹配处理(通配符展开); (2). 可出现在规则的命令中,通配符的通配处理是在shell在执行此命令时完成的。 5、在变量的定义和函数引用时,通配符将失效。所以需要使用“wildcard”函数(变量定义为“objects=$(wildcard *.o)”)使object为.o文件列表 6、Makefile的搜索变量VPATH,。make搜索目录的顺序是按照变量“VPATH”定义中的目录顺序进行的. 7、关键字vpath,可以为不同类型的文件(由文件名区分)指定不同的搜索目录. (1)、vpath PATTERN DIRECTORIES 为所有符合模式“PATTERN”的文件指定搜索目录“DIRECTORIES”。多个目录使用空格或者冒号(:)分开。类似上一小节的“VPATH”变量。 (2)、vpath PATTERN 清除之前为符合模式“PATTERN”的文件设置的搜索路径。 (3)、vpath 清除所有已被设置的文件搜索路径。 例:vpath %.h ../headers 8.自动化变量“$^”代表所有通过目录搜索得到的依赖文件的完整路径名(目录 + 一般文件名)列表。 “$@”代表规则的目标。自动化变量“$<”代表规则中通过目录搜索得到的依赖文件列表的第一个依赖文件。 9、“-lNAME”的依赖文件名 (1). make在执行规则时会在当前目录下搜索一个名字为“libNAME.so”的文件; (2). 如果当前工作目录下不存在这样一个文件,则make会继续搜索使用“VPATH”或者“vpath”指定的搜索目录。 (3). 还是不存在,make将搜索系统库文件存在的默认目录,顺序是:“/lib”、“/usr/lib”和“PREFIX/lib”(在Linux系统中为“/usr/local/lib”,其他的系统可能不同)。 10、伪目标是这样一个目标:它不代表一个真正的文件名,在执行make时可以指定这个目标来执行其所在规则定义的命令,有时也可以将一个伪目标称为标签。 此目标的目的为了执行执行一些列命令,而不需要创建这个目标。 将一个目标声明为伪目标的方法是将它作为特殊目标.PHONY”的依赖。 11、伪目标的另外一种使用场合是在make的并行和递归执行过程中。此情况下一般会存在一个变量,定义为所有需要make的子目录。对多个目录进行make的实现方式可以是:在一个规则的命令行中使用shell循环来完成。如下: SUBDIRS = foo bar baz subdirs: for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir; \ done 12、在Makefile中,一个伪目标可以有自己的依赖(可以是一个或者多个文件、一个或者多个伪目标) 13 make存在一个内嵌隐含变量“RM”,它被定义为:“RM = rm –f” 14、强制目标(没有命令或依赖的规则) clean: FORCE rm $(objects) FORCE: 15、空目标文件 print: foo.c bar.c lpr -p $? touch print 16、Makefile的特殊目标:.PHONY:标识伪目标 17、多目标 kbd.o command.o files.o: command.h 18、多规则目标 objects = foo.o bar.o foo.o : defs.h bar.o : defs.h test.h $(objects) : config.h 19、执行“make extradeps=foo.h”那么“foo.h”将作为所有的.o文件的依赖文件。 extradeps= $(objects) : $(extradeps) 20、静态模式:规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。 objects = foo.o bar.o all: $(objects) $(objects): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ 21、filter函数 过滤不符合“%.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 $< 22、双冒号规则(惹为普通规则时因两个相同目标而报错) Newprog :: foo.c $(CC) $(CFLAGS) $< -o $@ Newprog :: bar.c $(CC) $(CFLAGS) $< -o $@ 23、自动产生依赖 -M”选项gcc将自动找寻源文件中包含的头文件,并生成文件的依赖关系。 其输出结果中也包含对标准库的头文件的依赖关系描述。当不需要在依赖关系中考虑标准库头文件时,对于gcc需要使用“-MM”参数。 ########################################################################## 第五章:规则的命令 ########################################################################## 1、规则的命令由一些shell命令行组成,它们被一条一条的执行。规则中除了第一条紧跟在依赖列表之后使用分号隔开的命令以外,其它的每一行命令行必须以[Tab]字符开始。 2、命令回显:以@开头的命令将不会回显。 3、使用make的命令行参数“-n”或“--just-print”,那么make执行时只显示所要执行的命令,但不会真正的去执行这些命令 4、make参数“-s”或“--slient”则是禁止所有执行命令的显示,就好像所有的命令行均使用“@”开始一样。 5、在Makefile中书写在同一行中的多个命令属于一个完整的shell命令行,书写在独立行的一条命令是一个独立的shell命令行。因此:在一个规则的命令中,命令行“cd”改变目录不会对其后行的命令的执行产生影响。 6、并发执行命令,通过make的命令行选项“-j”或者“--job”来告诉make在同一时刻可以允许多条命令同时被执行(make的并发会产生非常多的问题) 7、命令执行的错误,命令之前加一个减号“-”(在[Tab]字符之后),来告诉make忽略此命令的执行失败。 8、在执行make时,如果使用命令行选项“-i”或者“—ignore-errors”, make将忽略所有规则中命令执行的错误。 9、一般make的“-k”参数在实际应用中,主要用途是:当同时修改了工程中的多个文件后,“-k”参数可以帮助我们确认对那些文件的修改是正确的(可以被编译),那些文件的修改是不正确的(不能正确编译) 10、make的递归执行 make的递归过程指的是:在Makefile中使用“make”作为一个命令来执行本身或者其它makefile文件的过程。 例: subsystem: cd subdir && $(MAKE) 其等价于规则: subsystem: $(MAKE) -C subdir 11、“CURDIR”,此变量代表make的工作目录。当使用“-C”选项进入一个子目录后,此变量将被重新赋值。 12、需要将一个在上层定义的变量传递给子make,应该在上层Makefile中使用指示符“export”对此变量进行声明。格式如下: export VARIABLE... 不传给子make时: unexport VARIABLE... 13、一个不带任何参数的指示符“export”指示符:export 含义是将此Makefile中定义的所有变量传递给子make过程。 14、在多级递归调用的make执行过程中。变量“MAKELEVEL”代表了调用的深度。 ########################################################################## 第六章:Makefile中的变量 ########################################################################## 1、在Makefile的目标、依赖、命令中引用变量的地方,变量会被它的值所取代(与C语言中宏引用的方式相同,因此其他版本的make也把变量称之为“宏”。 2、变量可以用来代表一个文件名列表、编译选项列表、程序运行的选项参数列表、搜索源文件的目录列表、编译输出的目录列表和所有我们能够想到的事物。 3、变量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串。 4、另外有一些变量名只包含了一个或者很少的几个特殊的字符(符号)。称它们为自动化变量。像“$<”、“$@”、“$?”、“$*”等 5、变量的引用方式是:“$(VARIABLE_NAME)”或者“${ VARIABLE_NAME }”来引用一个变量的定义。 6、一般在我们书写Makefile时,各部分变量引用的格式我们建议如下: (1). make变量(Makefile中定义的或者是make的环境变量)的引用使用“$(VAR)”格式,无论“VAR”是单字符变量名还是多字符变量名。 (2). 出现在规则命令行中shell变量(一般为执行命令过程中的临时变量,它不属于Makefile变量,而是一个shell变量)引用使用shell的“$tmp”格式。 (3). 对出现在命令行中的make变量我们同样使用“$(CMDVAR)” 格式来引用。 7、递归方式展开变量 用=或define定义的, 8.“直接展开”式。这种风格的变量使用“:=”定义。在使用“:=”定义变量时,变量值中对其他量或者函数的引用在定义变量时被展开(对变量进行替换)。所以变量被定义后就是一个实际需要的文本串,其中不再包含任何变量的引用。 x := foo y := $(x) bar x := later 就等价于: y := foo bar x := later 9."?="操作符 只有此变量在之前没有赋值的情况下才会对这个变量进行赋值。例如: FOO ?= bar 其等价于: ifeq ($(origin FOO), undefined) FOO = bar endif 10.变量的替换引用 foo := a.o b.o c.o bar := $(foo:.o=.c) 变量“bar”的值就为“a.c b.c c.c” 11. |
|
来自: 海漩涡 > 《Makefile笔记》