序 言
本系列笔记来自于徐海兵的《GNU make中文手册》,在此首先感谢徐海兵对于Info make的翻译。
第一章 概述
1.1 概述
GNU make:构建、管理工程;
makefile:描述整个工程的编译、链接等规则;
make:命令工具,解释makefile中的指令/规则;不仅仅用来管理C语言工程。
1.2 准备知识
编译:源文件-生成.o
链接:.o、库-可执行程序,ld工具;
静态库:多个.o文件的归档,ar工具;
动态库:也是多个.o文件的集合,但生成方式特殊;
第二章 GNU make介绍
2.1 makefile简介
make通过比较对应文件(目标和依赖)的最后修改时间,
来决定哪些文件需要更新;
make命令也可以通过命令行参数指定需要重新编译的文件;
make根据makefile中的规则描述,执行相关的命令来完成指定的任务;
首次编译:对所有源文件进行编译,并链接生成可执行程序;
非首次编译:重新编译自上次make之后修改过的源文件、包含了修改过的头文件的源文件;
自上次make之后没有修改的文件,不做任何工作;
2.2 makefile规则介绍
Target... : Prerequisites...
Command
…...
目标Target:最终可执行程序文件名、中间过程文件名.o、执行动作名(伪目标,如clean);
依赖Prerequisite:生成目标所需的文件名列表;
命令Command:规则所要执行的动作,shell命令;
注:每个命令行必须以[TAB]字符开始;
每一条规则可以有多条命令行;
一个目标可以没有依赖,而只有动作;
总之,规则描述了在什么情况下(依赖的文件发生变化)、如何重建规则的目标文件(执行命令描述的动作),它包含了文件间的依赖关系和更新此规则目标所需要的命令。
2.3 简单的示例
略
注:反斜线(\)为续行符,但其后必须不能有空格;
命令行都以[TAB]开始,但不是所有以[TAB]开始的都是命令行。规定:第1条规则出现之后的、所有以[TAB]开始的都作为命令行对待。
伪目标(phony targets):没有依赖,只有动作;如clean,不是文件,仅代表一个动作的标识。
2.4 make如何工作
终极目标:默认情况下,makefile中的第1条规则里面的第1个目标。
首先解析终极目标所在的规则;
然后为其第1个依赖文件寻找创建规则,若它又依赖于其他文件,则继续寻找;直到为所以的依赖文件找到了合适了创建规则。此时从最后一个规则回退执行,从而完成第1个依赖文件的创建/更新;
按上述同样的过程,依次完成终极目标的第2、3...个依赖文件的创建/更新;
最终,根据终极目标所在的规则,完成终极目标的创建/更新。
注:中间任意一个规则执行出现错误的话,make将立即报错退出;
make仅仅是执行规则,而对规则所描述的依赖关系的正确性、命令的正确性,不做任何判断。这2个方面需要makefile来保证。
2.5 指定变量
objects = main.o display.o utils.o
edit: $(objects)
cc -o edit $(objects)
2.6 自动推导规则
make本身的默认规则(make隐含规则):能够自动通过cc -c命令、完成.c文件的编译,生成同名的.o文件。
main.o: main.c defs.h
cc -c main.c
就可以简写为:
main.o: defs.h
2.7 另类风格的makefile:不推荐
之前是根据目标对规则进行分组、单目标、多依赖;
另类是根据依赖对规则进行分组、多目标、单依赖;
2.8 清除工作目录过程文件
规则除了能完成源代码编译之外,还能完成其他任务;
.PHONY: clean
clean:
-rm edit $(objects)
其中,特殊目标.PHONY将目标clean声明为伪目标;可以防止目录下存在clean文件时无法编译,-为忽略执行错误。
第三章 Makefile总述
3.1 Makefile的内容
完整的makefile包括5个东西:显式规则、隐含规则、变量定义、指示符、注释。
显式规则:何时、如何更新1个或多个目标(文件);
隐含规则:根据目标名,自动推导出依赖文件、命令;
变量定义:使用字符或字符串代替一段文本串;
makefile指示符:指明make在读取makefile时要执行的一个动作,如:包含、条件执行、定义一个多行变量等;
注释:#,可以使用\续行。
注:第一条规则之后的所有[TAB]开始行,将被送往shell执行,包括[TAB]开始的注释#...;
指示符define可以定义多行变量或命令包,在使用该多行变量的地方,将发生基于文本的展开,类似于宏。
3.2 makefile文件的命名
默认情况下,make将在工作目录下,按以下文件名依次查找、读取并执行:GNUmakefile(仅GNU make识别)、makefile、Makefile。
当找不到以上3个文件中任何一个时,make将不读取其他文件作为解析对象。但根据make的隐含规则,可以通过命令行指定一个目标,如make foo.o。
当makefile文件名不是3文件之一时,可以通过make的-f(或者--file)选项来指定。选项可以指定多个makefile文件,具有选项时,make将不再自动寻找3文件。
3.3 包含其他makefile文件
“include”指示符:include FILENAMES...,可包含多个,使用空格或TAB隔开,可以使用通配符。
如:include foo *.mk $(bar)。此时make将转而去读取指定的文件,读取完返回。
场合:通用的变量、模式规则;包含自动生成的依赖文件。
当include的文件不是绝对路径指定、也不在当前目录下时,依次在以下目录中寻找:-l(或—include-dir)指定的目录、/usr/gnu/include/、/usr/local/include、/usr/include;
如果均未找到,make将警告提示但不退出,继续处理makefile后面的内容;
当完成读取整个makefile后,make将试图使用规则来创建include指示符指定、但是之前未找到的文件,如果创建失败,make将提示致命错误并退出,提示:
Make: ***No rule to make target '<filename>'.Stop
-include(或sinclude):忽略并继续。
3.4 变量MAKEFILES
环境变量MAKEFILES如果被设置,则make时首先将此变量的值作为需要读入的makefile文件。
与include类似,如果MAKEFILES指定的非绝对路径,按照和include同样的规则去查找,但与include的区别:
MAKEFILES中的目标不能作为make的终极目标,make执行时的终极目标是当前目录下3文件之一中定义;
MAKEFILES中定义的文件找不到时,不会导致make错误;
make执行时,首先读取MAKEFILES指定的文件列表、再读取命令行-f指定的文件、当前目录下的3文件之一、遇到include时采取读取包含的文件,最后解析执行。
不推荐设置MAKEFILES,可能使用include替代。
3.5 变量MAKEFILE_LIST
make读取MAKEFILES指定的文件、命令行指定的文件、3文件名之一makefile、include之后,解析执行之前,会将读取的文件名依次追加到MAKEFILE_LIST变量。此变量的最后一个字,就是make当前正在处理的makefile文件名。
include inc.mk
name := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST) ),name的值为inc.mk。
3.6 其他特殊变量
GNU make支持特殊变量.VARIABLES:在出现处被展开为此引用点之前定义的所有全局变量列表,不能被赋值。
包含空变量、make内嵌变量,不包含目标指定的变量。
3.7 makefile文件的重建
如果makefile由其他文件生成/重建,make在开始解析这个makefile时会重新读取更新后的makefile。
make在读入所有makefile后,将每个makefile作为一个目标,寻找其规则;如果存在明确或隐含规则,就会更新该makefile;完成所有更新后,如果之前读取的文件有被更新的,则重新读取一遍所有的makefile文件(重新读取之后仍然会试图更新、重建每一个makefile)。
实际中一般会明确给出makefile,不需要由make重建,但make执行时总是试图重建/更新那些已存在的makefile。
若双冒号规则(一条没有依赖只有命令行的规则,每次make时目标将会被无条件更新)的目标是makefile,将产生死循环。因此,make在处理时,将忽略目标为makefile文件的双冒号规则。
3文件之一的makefile若不存在,但可以通过隐含规则创建,则make将自动创建缺省makefile文件。
如果目标是makefile文件,make时的-t(--touch)、-q(--question)、-n(--just-print)选项更新makefile目标无效(???)。
3.8 重载另外一个makefile
问题起源:当include进来的makefile中存在和当前makefile中目标同名、但是命令不同时,这是非法的。
此时,将不能采用include方式,可以使用如下形式:
#sample of GNUmakefile
foo:
frobnicate > foo
%:force
@$(MAKE) -f Makefile $@
force:;
说明:当make foo时,按前一条规则执行;当make bar时,GNUmakefile中找不到bar目标,将使用%(所有匹配模式)来重建/更新bar目标,即执行$(MAKE) -f Makefile bar。
相当于“include”进了Makefile文件(但是当Makefile中有和GNUmakefile中同名的目标时,执行GNUmakefile中的规则,Makefile中的规则将不起作用)。
%-所有模式匹配规则:可以匹配任意目标。
%的依赖force:保证了即使目标已存在也会执行本规则。
force规则中空命令:防止make在找不到创建force的规则时,又递归性的匹配%来创建force,陷入死循环。
3.9 make如何解析makefile文件
make的执行过程分为2个阶段:
链表阶段:读取所有的makefile文件(MAKEFILE变量指定的、命令行-f选项指定、当前目录下的3缺省文件、include进来的),内建所有变量、明确规则、隐含规则,建立所有目标、依赖之间的依赖关系结构链表。
重建阶段:根据链表,判断哪些目标需要更新、重建。
变量和函数的展开问题:和2阶段有关,如果在第1阶段被展开,称为“立即展开”;如果在必须使用时或第2阶段展开,称为“延后展开”。
变量取值:IMMEDIATE =或?= DEFERRED
IMMEDIATE := IMMEDIATE
IMMEDIATE += DEFER or IM
define IMMEDIATE
DEFERRED
Endef
条件语句:均为立即展开
所有规则:IMMEDIATE : IMMEDIATE ; DEFERRED
DEFERRED
来源:https://www.cnblogs.com/chinawine/archive/2012/04/10/2439888.html