【注】:文中所指手册皆为GNU make Version 4.1shell
一、make的通常特性
1.一、Makefiles的构成
Makefiles包含五种元素: 显式规则(explicit rules), 隐式规则(implicit rules), 变量定义(variable definitions),指令(directives), 和注释(comments)。其中没有提到函数,函数应该归于变量之中吧。函数
- 显式规则:指导什么时候和怎样更新一个或多个文件(targets)。
- 隐式规则
1.二、make如何读入makefile【手册3.7节】
GNU经过两步彻底分离的步骤来完成这项工做。(其实我以为是三步,由于第一步明显地分红两个阶段)第一阶段(read-in),make读全部相关的makefile(包括include makefiles),创建起其中的变量和规则(makefile就是由变量和规则组成的?);而后构建target和prerequisites的依赖关系;第二阶段(target-update),make利用前一步整理的关系决定哪一个target须要重建,从而调用相应的规则。ui
make的这种“两步”工做方式决定了变量和函数的两种不一样的展开方式:当即展开、延迟展开。当即展开是在第一阶段前期作的,(我的理解就是边读边展开);延迟展开是在第一阶段后期甚至第二阶段才作的(我的理解是在全部makefile都读入之后,整理各变量和规则依赖关系时展开)递归
变量赋值ip
- immediate = deferred
- immediate ?= deferred
- immediate := immediate
- immediate ::= immediate
- immediate += deferred or immediate
- immediate != immediate
变量名都是理解展开的,变量值则分状况了。ci
规则定义(规则都是一种展开方式,无论它是什么形式的)
immediate : immediate ; deferred
deferredrem
二、变量
通常规则:get
- 变量是一个字符序列,这个序列绝对不能包含‘:’, ‘#’, ‘=’,和空白这四类字符,除数字、字母、下划线的自它字符也要当心使用;
- 变量名区分大小写;
- 变量引用使用变量引用符号'$'加圆括号或大括号。如‘$(foo)’ or ‘${foo}’都是对foo变量的引用;
- 若是变量名只有一个字符,引用变量时括号能够省去,譬如$x,但官方不建议这样作,这个作法是保留给自动变量使用的;
两种变量:递归变量、简单变量 (很是重要)it
- 递归展开变量是用“=”符号或define指令定义的变量;
- 简单展开变量是用‘:=’ or ‘::=’符号定义的变量,这两种符号对GNU是同样的,但POSIX只认‘::=’
- 简单变量在定义时就对它的值进行展开,而递归变量只有在须要展开时才对它的值进行展开;
- 递归变量的优势在于它能够引用后面定义的变量,由于它的展开在make读makefile的第二阶段
【例1】:递归变量与简单变量定义io
三、规则
3.一、规则通常特性:
targets(目标) ... : prerequisites (依赖)... ; recipes
recipes
...
- recipe在prerequisites的下一行以tab键开始(tab键可使用.RECIPEPREFIX变量的第一个值代替,【手册6.14节】);
- recipe还能够紧跟在prerequisites的同一行,以“;”分隔。这个方法在定义“空recipe”时很是有效;
- 规则除了用于编译程序,还能用来干其它事情,见【手册2.7节】;
3.一、规则分类
- 规则分显式规则、隐式规则;
- 隐式规则又分为内建隐式规则(built-in implicit rules)和自定义隐式规则,又叫模式规则(pattern rules)【手册10】;
- 自定义隐式规则还有一种方法叫后缀规则(Suffix rules)【手册10】;
- 和模式规则相比,后缀规则有使用限制,但它是老技术,使用它能够保留兼容性【手册10】;
- 隐式规则能够链式调用(譬如:a.c -> a.y -> a.o)【手册10】;
3.三、显式规则
3.四、隐式规则
- 不少文件的remake工做都是标准的,依照惯例的,因此咱们能够不用为这些文件的更新制定规则,这就是隐式规则;
- 咱们想要target使用隐式规则,惟一要作的就是不要给target指定recipe(空recipe规则)甚至不给target写规则;
- 事实上,不少时候咱们要作的是阻止隐式规则发挥做用;
规则作什么
规则还能作什么
3.二、Prerequisites
四、符号
4.一、@
@出如今recipe的最前面用于关闭recipe回显,见【手册5.2节】
$@
4.二、$
变量的引用符号
4.三、通配符
- 跟Bourne Shell同样,make的通配符也是‘*’, ‘?’ and ‘[...]’(...表示[]中的内容很丰富);
- 规则中的通配符:targets和prerequisites中的通配符展开是由make来完成的;recipes中的通配符展开则是由shell来完成的;
- 变量中的通配符make是不展开的;
- 但含有通配符的变量用在规则中,变量和通配符都会被展开;
- 要让变量中的通配符生效,可使用wildcard函数;
- 文件名中的通配符'*',譬如*.o
- 表明匹配全部的“o”文件;
- 若是搜索目录里没有任何一个“o"文件,则“*.o”表明它的字面意思;
- 若是搜索目录里也没有“*.o”文件(几乎是必定的),则make可能会报错;
- wildcard函数
- 能够用于make不进行通配符展开的地方,譬如变量和函数参数;
- 跟直接使用通配符相比,它也有优点,当没有匹配时它输出空,不会出现使用字面含义的状况;
【4.3例1】
objects = *.o
解释: 因为通配符是在变量的值中,因此这个变量就是字面的意思,而不是表明全部的“o”文件,可是,若是这个变量出如今prerequisites,“*”就是通配符。
【4.3例2】
objects := $(wildcard *.o)
四、依赖
依赖类型