Make学习二:makefile组成要素
系列文章目录
Make学习一:make初探
文章目录
- 系列文章目录
- 前言
- makefile 组成
- makefile中的长行拆分
- 给 Makefile 取什么名字
- 包含其他 Makefile
- Makefile 如何被解析
- 总结
前言
make初探 中初步使用了 Makefile 这个工具并知道 makefile 告诉 make 如何重新编译系统的信息。本篇文章负责理解 Makefile 的组成要素。
makefile 组成
Makefile 主要包含以下五种内容:
- 显示规则:明确告诉 make 什么时候、如何去重新生成(更新)一个或多个文件。规则中的 目标(targets) 是要生成的文件,依赖(prerequisites) 是生成这些目标所依赖的文件,配方(recipe) 是具体的命令。
- 隐式规则:隐式规则:通过文件名的模式匹配,告诉 make 如何去更新一类文件。(例如 .c 文件如何生成 .o 文件,不需要每次都手写规则。)
- 变量定义:用来保存一些字符串,可以在 Makefile 里多次使用。
- 指令:是对 make 本身行为的控制。例如:include(包含其他 Makefile),if / else / endif(条件判断),define / endef(多行变量定义)
- 注释:用 # 开头,后面的内容都不被 make 解析。如果想写出 # 字符本身,可以用 #。
makefile中的长行拆分
Makefile 使用 基于行的语法,每一行(换行符 \n)是一个语句的结束标志。语句太长是可以换行写的,不受长度限制(只受内存限制)。
用反斜杠 \ 在行末续行,可以把一条逻辑语句分成多行。
反斜杠 \ + 换行 的处理方式,在 配方行(recipe line) 和 非配方行(non-recipe line) 中略有不同。(这里讲的是非配方行,配方行会在后面文章中再讲。)
在非配方行(recipe line) (比如变量定义):
- \ + 换行 会被转换成 一个空格;
- \ 前后的所有空白字符(比如空格或 Tab)也会合并为 一个空格;
- 如果连续有多个 \ 换行,也都合并为一个空格。
FOO = one \two \three
如果你拆分一行但又不想在拆分点多出一个空格,可以用这个技巧:
var := one$\ word
这会被解释为:var := oneword
,原因在于展开反斜杠加换行之后,$ 后跟一个空格是在引用空格变量的内容(" "),但这个变量并不存在没有定义,所以展开为空字符串。
给 Makefile 取什么名字
默认情况下,make 查找 Makefile 文件时,会按照这个顺序去找:GNUmakefile、makefile、Makefile
推荐用 Makefile,因为:
- 在 ls 目录列表时,Makefile 会出现在靠前的位置(大写字母排在小写之前)
- 和 README 等重要文件放在一起,容易一眼看到。
如果你不用默认名字(比如 Makefile),而是用其他名字,比如 build.mk,你需要在命令行用 -f 或 --file 指定,例如:make -f build.mk
。
包含其他 Makefile
include 指令的作用是:暂停当前 makefile 的读取,去读取一个或多个其他的 makefile 文件,读完再继续当前的。例如:include vars.mk
如果文件名不是绝对路径、也不在当前目录,make 会搜索其他目录,比如:用 -I 指定的路径:make -I path/to/includes
。或者一些系统默认路径(如 /usr/include)。当前有效的搜索路径可以通过 .INCLUDE_DIRS 变量查看。
Makefile 如何被解析
GNU make 读取 Makefile 是 一行一行读取的。每读一行,就根据这一行的内容去解析它。碰到 \ 换行时续行;
make 是通过 每一行的第一个字符 来判断这一行是属于哪种类型:
- Tab 配方(recipe)
- # 注释(comment)
- 其他 规则(rule)、变量定义(variable)、指令(directive)
变量会在不同的时机被展开,这取决于具体的上下文。这个具体展开时机,会在后面详细讲,我们这里先知道有“递归展开”和“立即展开”两种方式。
总结
完结撒花!!