这篇文档主要是用作《跟我一起写Makefile》教程的笔记,不会面面俱到,只记录关键点。
<!—more—>
[TOC]
概述
- makefile的最大优点——自动化编译
- make是一个命令工具,是一个解释makefile中指令的命令工具
程序的编译与链接
- 编译(compile):由源文件生成目标文件(.o),只要求
- 语法正确
- 函数和变量的声明正确(需要告诉编译器头文件的位置)
- 链接(link):使用中间目标文件生成应用程序,也就是可执行文件
- 主要链接函数和全局变量,也就是要在目标文件中寻找函数的实现
- 一般情况下,我们都会对中间目标文件进行打包,在windows下形成库文件(library file),也就是
.lib
文件,而在linux下是Archive File,后缀为.a
文件。
Makefile简介
- make命令执行,需要有一个makefile文件
makefile规则
|
|
- target :可以是一个object file(目标文件), 也可以是一个执行文件, 还可以是一个标签 (label)。
- prerequisites :生成该target所依赖的文件和/或target
- command:该target要执行的命令(任意的shell命令)
简言之:prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。
makefile示例
|
|
几个注意点:
- 反斜杠(\)是换行符
- 在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个 Tab 键作为开头。
- clean只是一个label,make不会自动执行其后的命令,这样的方法非常有用,我们可以在一个makefile中定义不用的编译或是和编译无关的命令,如打包备份等
- 工作流程
- make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
- 如果找到, 它会找文件中的第一个目标文件(target), 在上面的例子中, 他会找 到“edit”这个文件,并把这个文件作为最终的目标文件。
- 如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修改时间要比 edit 这个文 件新,那么,他就会执行后面所定义的命令来生成 edit 这个文件。
- 如果 edit 所依赖的 .o 文件也不存在,那么make会在当前文件中找目标为 .o 文件的依 赖性,如果找到则再根据那一个规则生成 .o 文件。(这有点像一个堆栈的过程)
- 当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生 成make的终极任务,也就是执行文件 edit 了。
- make对于所定义的命令的错误,或是编译不成功,不会报错,只有依赖文件找不到时才会报错
Makefile中使用变量
对于重复的字符串
,我们可以使用变量避免重复书写。makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。
变量定义:
12objects = main.o kbd.o command.o display.o \insert.o search.o files.o utils.o变量使用:
$(objects)
Makefile自动推导
GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令。
只要make看到一个 .o 文件, 它就会自动的把 .c 文件加在依赖关系中, 如果make找到 一个 whatever.o , 那么 whatever.c 就会是 whatever.o 的依赖文件,并且 cc -c whatever.c 也会被推导出来,因而上面命令可以写为
|
|
也就是:对应于目标文件的源文件以及相应的编译命令cc -c
都不需要显式写出。这就是所谓的隐晦规则。
清空目标文件的规则
|
|
.PHONY
表示clean是一个伪目标文件- 在 rm 命令前面加了一个小减号的意思 就是, 也许某些文件出现问题, 但不要管, 继续做后面的事。
- “clean从来都是放在文件的最后”
makefile包含内容
- 显式规则。显式规则说明了如何生成一个或多个目标文件。这是由Makefile的书写者明显 指出要生成的文件、文件的依赖文件和生成的命令。
- 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较简略地 书写Makefile,这是由make所支持的。
- 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像 你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
- 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言 中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的 预编译#if一样;还有就是定义一个多行的命令。
- 注释。Makefile中只有行注释, 和UNIX的Shell脚本一样, 其注释是用 # 字符, 这个就 像C/C++中的 // 一样。 如果你要在你的Makefile中使用 # 字符, 可以用反斜框进行转 义,如: # 。
Makefile文件名
- 建议使用Makefile这个作为文件名
- 可 以 使 用 别 的 文 件 名 来 书 写Makefile, 比如:“Make.Linux”,等 , 如 果 要 指 定 特定的Makefile, 你可以使用make的
-f
和—file
参数,如:make -f Make.Linux
或make --file Make.AIX
引用其他Makefile
- 语法:
include filename
- 注意点:
- filename 可以是当前操作系统Shell的文件模式(可以包含路径和通配符)
- 如果文件都没有指定绝对路径或是相对路径的话,make会 在当前目录下首先寻找,如果当前目录下没有找到,那么,make还会在下面的几个目录下找:
- 如果make执行时,有 -I 或 –include-dir 参数,那么make就会在这个参数所指定的 目录下去寻找。
- 如果目录 \
/include (一般是: /usr/local/bin 或 /usr/include )存 在的话,make也会去找。
-include <filename>
:无论include过程中出现什么错误,都不要报错继续执行。
Make工作方式
- 读入所有的Makefile。
- 读入被include的其它Makefile。
- 初始化文件中的变量。
- 推导隐晦规则,并分析所有规则。
- 为所有的目标文件创建依赖关系链。
- 根据依赖关系,决定哪些目标要重新生成。
- 执行生成命令。