type
status
date
slug
summary
tags
category
icon
password
make 简介
Themake
utility automatically determines which pieces of a large program need to be recompiled, and issues commands to recompile them.
Makefile 结构
makefile 的内容由多个 rule 组成。
rule 大概长这样:
rule 相关概念
target
可以是一个object file(目标文件),也可以是一个可执行文件,还可以是一个标签(label)。对于标签这种特性,在后续的“伪目标”章节中会有叙述。
prerequisites
生成该target所依赖的文件和/或target。
recipe
该target要执行的命令(任意的shell命令)。
prerequisites中如果有一个以上的文件比target文件要新的话,recipe所定义的命令就会被执行。
make 工作原理
GNU的make工作时的执行步骤如下:
- 读入所有的Makefile。
- 读入被include的其它Makefile。
- 初始化文件中的变量。
- 推导隐式规则,并分析所有规则。
- 为所有的目标文件创建依赖关系链。
- 根据依赖关系,决定哪些目标要重新生成。
- 执行生成命令。
默认的情况下,make命令会在当前目录下按顺序寻找文件名为
GNUmakefile
、 makefile
和 Makefile
的文件。在这三个文件名中,最好使用 Makefile
这个文件名,因为这个文件名在排序上靠近其它比较重要的文件,比如 README
。包含其它 Makefile
在Makefile使用
include
指令可以把别的Makefile包含进来, ,被包含的文件会原模原样的放在当前文件的包含位置。
环境变量 .INCLUDE_DIRS
包含当前 make 会寻找的目录列表。你应当避免使用命令行参数 -I
来寻找以上这些默认目录,否则会使得 make
“忘掉”所有已经设定的包含目录,包括默认目录。如果你的当前环境中定义了环境变量
MAKEFILES
,那么make会把这个变量中的值做一个类似于 include
的动作。这个变量中的值是其它的Makefile,用空格分隔。只是,它和 include
不同的是,从这个环境变量中引入的Makefile的“默认目标”(the default goal)不会起作用,如果环境变量中定义的文件发现错误,make也会不理。建议不要使用这个环境变量。通配符
make支持三个通配符:
*
, ?
和 ~
。这是和Unix的B-Shell是相同的。如果我们的文件名中有通配符,如:
*
,那么可以用转义字符 \
,如 \*
来表示真实的 *
字符,而不是任意长度的字符串。
波浪号( ~
)字符在文件名中也有比较特殊的用途。如果是 ~/test
,这就表示当前用户的 $HOME
目录下的test目录。而 ~user/test
则表示用户 user 的宿主目录下的 test 目录。
通配符同样可以用在变量中。但是在变量中不会展开,因为变量类似于 C/C++ 中的宏。
注意以下两个写法的区别:伪目标
“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显式地指明这个“目标”才能让其生效。
为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显式地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。
伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”,只要将其放在第一个。
条件判断
条件表达式的语法为:
以及:
<conditional-directive>
可以是- ifeq
- ifneq
- ifdef
- ifndef
函数调用
函数调用,很像变量的使用,也是以
$
来标识的,其语法如下:$(
<function> <arguments>
)
或是:
${<function> <arguments>}
这里,
<function>
就是函数名,make支持的函数不多。 <arguments>
为函数的参数,参数间以逗号 ,
分隔,而函数名和参数之间以“空格”分隔。函数调用以 $
开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使用变量,为了风格的统一,函数和变量的括号最好一样,如使用 $(subst a,b,$(x))
这样的形式,而不是 $(subst a,b, ${x})
的形式。因为统一会更清楚,也会减少一些不必要的麻烦。
用法细节
换行
使用反斜杠(
\
)定义变量
为了makefile的易维护,在makefile中我们可以使用变量。
通过
$(变量名)
引用变量。自动推导
只要make看到一个
.o
文件,它就会自动的把 .c
文件加在依赖关系中,如果make找到一个 whatever.o
,那么 whatever.c
就会是 whatever.o
的依赖文件。并且 cc -c whatever.c
也会被推导出来。在不同位置声明target的依赖
clean
每个Makefile中都应该写一个清空目标文件(
.o
)和可执行文件的规则,这不仅便于重编译,也很利于保持文件的清洁。前面说过,
.PHONY
表示 clean
是一个“伪目标”。而在 rm
命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。