GNU Make总结
整理自文档 <<跟我一起写Makefile>>
核心规则
target ... : target所依赖的target ...
生成target的命令
其中target可以是object文件,也可以是一个可执行文件,亦可以是一个标签。
本质上讲,make就是一个以目标为终点的系统,而目标与目标之间通过依赖关系组成一个关系链。
make工作机制
在默认的方式下,也就是我们只输入 make 命令。那么,
-
make 会在当前目录下找名字叫 Makefile或makefile的文件。
-
如果找到,它会找文件中的第一个目标文件(target) 你也可以指定具体的目标。
-
如果目标文件不存在,或是目标所依赖的文件的修改时间要比目标文件新,那么,他就会执行后面所定义的命令来生成依赖的目标文件。
-
如果目标所依赖的文件也不存在,那么 make 会在当前文件中找依赖文件的依赖性,如果找到则再根据那一个规则生成依赖文件。(这有点像一个堆栈的过程)
这就是整个 make 的依赖性, make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目
标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么 make 就会直接退出,并
报错,而对于所定义的命令的错误,或是编译不成功, make 根本不理。 make 只管文件的依赖性,即,如
果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作。
工作步骤
- 读入所有的makefile
- 读入被 include 的其它 Makefile
- 初始化文件中的变量。
- 推导隐晦规则,并分析所有规则。
- 为所有的目标文件创建依赖关系链。
- 根据依赖关系,决定哪些目标要重新生成。
- 执行生成命令。
make变量的定义与引用
定义:
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
引用:
$(objects)
make自动推导
make可以根据文件名后缀推导出生成目标的规则。比如
main.o : defs.h 并不需要指定main.o 是根据main.o 是根据main.c, defs.h生成main.o
伪目标
.PHONY : clean
clean :
-rm edit $(objects)
其中, .PHONY 为伪目标,也就是它并不会产生输出。 -rm表示,如果删除文件中出错,比如某些文件不存在,忽略它,继续执行。
makefile 的组成成分
- 显示规则
明确声明如何生成一个目标或多个目标。 - 隐晦规则
自动推导生成目标 - 变量定义
- 文件指示
在文件中引用其他的makefile文件,
include
-include无论filename文件是否存在,都不报错。 - 注释
注释符号为 #
注意: 在 Makefile 中的命令,必须要以 Tab 键开始
命令行参数
- -I 或 --include-dir
make 就会在这个参数所指定的目录寻找导入的文件。如果目录/include
(一般是:/usr/local/bin 或 /usr/include )存在的话, make 也会去找。
规则
规则包含两个部分,一个是依赖关系,一个是生成目标的方法。
make 支持三个通配符:
- , ? 和 ~ 。这是和 Unix 的 B-Shell 是相同的。
多目标
Makefile 的规则中的目标可以不止一个,其支持多目标,有可能我们的多个目标同时依赖于一个文
件,并且其生成的命令大体类似。于是我们就能把其合并起来。当然,多个目标的生成规则的执行命令不
是同一个,这可能会给我们带来麻烦,不过好在我们可以使用一个自动化变量 $@ (关于自动化变量,将
在后面讲述),这个变量表示着目前规则中所有的目标的集合,这样说可能很抽象,还是看一个例子吧。
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@
上面的规则等价与
bigoutput : text.g
generate text.g -big > bigoutput
littleoutput : text.g
generate text.g -little > littleoutput
其中, -$(subst output,,$@) 中的 $ 表示执行一个 Makefile 的函数,函数名为 subst,后面的为
参数。关于函数,将在后面讲述。这里的这个函数是替换字符串的意思, $@ 表示目标的集合,就像一个
数组, $@ 依次取出目标,并执于命令。
静态模式
自动生成依赖
条件判断
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
其他语法ifneq(参数1,参数2) ,ifndef(参数1, 参数2), ifdef(参数1, 参数2)
make的运行
- 退出码 0 代表执行成功,1 代表 make遇到任何错误, 2 如果你使用了 make 的“-q”选项,并且 make 使得一些目标不需要更新,那么返回 2。
- 指定 makefile文件 make -f filename
其他
sources = foo.c bar.c
ifneq ( $(MAKECMDGOALS),clean)
include $(sources:.c=.d)
endif
有一个 make 的环境变量叫 MAKECMDGOALS ,这个变量中会存放你所指定的终极目标的列表,如果
在命令行上,你没有指定目标,那么,这个变量是空值。
默认规则
• all: 这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
• clean: 这个伪目标功能是删除所有被 make 创建的文件。
• install: 这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
• print: 这个伪目标的功能是例出改变过的源文件。
• tar: 这个伪目标功能是把源程序打包备份。也就是一个 tar 文件。
• dist: 这个伪目标功能是创建一个压缩文件,一般是把 tar 文件压成 Z 文件。或是 gz 文件。
• TAGS: 这个伪目标功能是更新所有的目标,以备完整地重编译使用。
• check 和 test: 这两个伪目标一般用来测试 makefile 的流程。
检查规则
有时候,我们不想让我们的 makefile 中的规则执行起来,我们只想检查一下我们的命令,或是执行
的序列。于是我们可以使用 make 命令的下述参数:
-n, --just-print, --dry-run, --recon 不执行参数,这些参数只是打印命令,不管目标是否更新,把
规则和连带规则下的命令打印出来,但不执行,这些参数对于我们调试 makefile 很有用处。
-t, --touch 这个参数的意思就是把目标文件的时间更新,但不更改目标文件。也就是说, make 假装编
译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。
-q, --question 这个参数的行为是找目标的意思,也就是说,如果目标存在,那么其什么也不会输出,
当然也不会执行编译,如果目标不存在,其会打印出一条出错信息。
-W
文件。一般是是源文件(或依赖文件), Make 会根据规则推导来运行依赖于这个文件的命令,一般
来说,可以和“-n”参数一同使用,来查看这个依赖文件所发生的规则命令。
另外一个很有意思的用法是结合 -p 和 -v 来输出 makefile 被执行时的信息(这个将在后面讲述)。
make 参数
下面列举了所有 GNU make 3.80 版的参数定义。其它版本和产商的 make 大同小异,不过其它产商
的 make 的具体参数还是请参考各自的产品文档。
-b, -m 这两个参数的作用是忽略和其它版本 make 的兼容性。
-B, --always-make 认为所有的目标都需要更新(重编译)。
-C
后面的路径以前面的作为相对路径,并以最后的目录作为被指定目录。如:“make -C ~hchen/test
-C prog”等价于“make -C ~hchen/test/prog”。
-debug[=
输出最简单的调试信息。下面是
• a: 也就是 all,输出所有的调试信息。(会非常的多)
• b: 也就是 basic,只输出简单的调试信息。即输出不需要重编译的目标。
• v: 也就是 verbose,在 b 选项的级别之上。输出的信息包括哪个 makefile 被解析,不需要被
重编译的依赖文件(或是依赖目标)等。
• i: 也就是 implicit,输出所以的隐含规则。
• j: 也就是 jobs,输出执行规则中命令的详细信息,如命令的 PID、返回码等。
• m: 也就是 makefile,输出 make 读取 makefile,更新 makefile,执行 makefile 的信息。
-d 相当于“–debug=a”。
-e, --environment-overrides 指明环境变量的值覆盖 makefile 中定义的变量的值。
-f=
-h, --help 显示帮助信息。
-i , --ignore-errors 在执行时忽略所有的错误。
-I
指定多个目录。
-j [
令时能运行多少就运行多少。如果有一个以上的“-j”参数,那么仅最后一个“-j”才是有效的。(注
意这个参数在 MS-DOS 中是无用的)
-k, --keep-going 出错也不停止运行。如果生成一个目标失败了,那么依赖于其上的目标就不会被执行
了。
-l
-n, --just-print, --dry-run, --recon 仅输出执行过程中的命令序列,但并不执行。
-o
的依赖文件新于它。
-p, --print-data-base 输出 makefile 中的所有数据,包括所有的规则和变量。这个参数会让一个简单
的 makefile 都会输出一堆信息。如果你只是想输出信息而不想执行 makefile,你可以使用“make
-qp”命令。如果你想查看执行 makefile 前的预设变量和规则,你可以使用“make –p –f /dev/null”。
这个参数输出的信息会包含着你的 makefile 文件的文件名和行号,所以,用这个参数来调试你的
makefile 会是很有用的,特别是当你的环境变量很复杂的时候。
-q, --question 不运行命令,也不输出。仅仅是检查所指定的目标是否需要更新。如果是 0 则说明要更
新,如果是 2 则说明有错误发生。
-r, --no-builtin-rules 禁止 make 使用任何隐含规则。
-R, --no-builtin-variabes 禁止 make 使用任何作用于变量上的隐含规则。
-s, --silent, --quiet 在命令运行时不输出命令的输出。
-S, --no-keep-going, --stop 取消“-k”选项的作用。因为有些时候, make 的选项是从环境变量
“MAKEFLAGS”中继承下来的。所以你可以在命令行中使用这个参数来让环境变量中的“-k”选
项失效。
-t, --touch 相当于 UNIX 的 touch 命令,只是把目标的修改日期变成最新的,也就是阻止生成目标的
命令运行。
-v, --version 输出 make 程序的版本、版权等关于 make 的信息。
-w, --print-directory 输出运行 makefile 之前和之后的信息。这个参数对于跟踪嵌套式调用 make 时
很有用。
--no-print-directory 禁止“-w”选项。
-W
要更新,如果和“-n”选项使用,那么这个参数会输出该目标更新时的运行动作。如果没有“-n”那
么就像运行 UNIX 的“touch”命令一样,使得
--warn-undefined-variables 只要 make 发现有未定义的变量,那么就输出警告信息。

浙公网安备 33010602011771号