Makefile自动化构建工具的使用
Makefile自动化构建工具的使用
Makefile的简介
一个工程中的源文件数不胜数,其按类型、功能、模块分别放在若干个目录中, makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
makefile 带来的好处就是——“自动化编译”,一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make 是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的 make 。可见, makefile 都成为了一种在工程方面的编译方法。
make 是一条命令, makefile 是一个文件,两个搭配使用,完成项目自动化构建。
依赖关系和依赖方法
示例:使用make指令将当前目录下的main.c文件编译生成一个名为hello的可执行程序。main.c的内容是非常简单的printf一句字符串hello world。
- 首先我们需要在构建项目的目录下创建一个名为 “Makefile” 或 “makefile” 的文件。然后以文本方式打开 Makefile 编写里头的内容,写上 依赖关系 和 依赖方法 :
hello:main.c 是 依赖关系 ,表示 hello 的生成需要依赖 main.c 这个文件, main.c 是 依赖文件 ,而 hello 是 目标文件 。
gcc main.c -o hello 是 依赖方法 ,表示生成 目标文件hello 所需要执行的方法。 注意:依赖方法必须以一个制表符Tab开头,即键入一个Tab,而不能以多个空格代替Tab。
- 然后我们保存并退出 Makefile 文件,执行 make 指令,就能帮我们自动执行生成 目标文件 的指令, hello 可执行文件就随之生成好了,就像在 Visual Studio 中的 生成解决方案 那样方便。
如果不想上面红框里的 gcc main.c -o hello 依赖方法 被 回显 出来,可以在 编辑Makefile的依赖方法前面加上 @。
保存并退出,我们 rm 掉之前生成 hello 可执行文件,再次运行一下 make 命令,这次就没有 依赖方法 的 回显 了。
清理项目
好了,现在可以使用 make 指令方便的构建项目了,那么现在我们要使用 make clean 来清理掉所构建的项目,就像在 Visual Studio 中的 清理解决方案 一样。
我们打开之前的 Makefile ,添加上如下的内容,目标文件 clean 的名字是用户 自定义 的, clean 没有对应的 依赖文件 :
保存退出,然后输入make clean命令:
我们的 hello 就顺利的被清理掉了,至于 .PHONY 干什么用,,后面详细讲解。
推导多个依赖关系
上面我们直接将 main.c 编译生成了 hello 的可执行文件。我们也可以像下面这样把编译链的过程详细写出来生成可执行文件, 依赖关系为hello -> main.o -> main.s -> main.i -> main.c :
保存退出,执行make命令:
这个过程有点类似于递归,即如果找不到生成 目标文件 所需的 依赖文 件,则会往下查看这个 依赖文件 是否可以通过其 依赖关系和对应的依赖方法 生成,不断进行上述过程,直到我们所需的 依赖文件 出现为止,然后 通过这个依赖文件不断回溯构造出每一层所需的依赖文件 ,如果该过程结束了还是没找到对应的 依赖文件 ,那么 makefile 则会终止执行并报错。
.PHONY
我们在上面使用 .PHONY 来定义 clean 为 伪目标 ,表示 目标文件clean 不是一个真实存在的文件,执行 make clean时能够直接执行对应的依赖方法 。 .PHONY适用于那些不生成实际文件的任务,如清理临时文件、构建依赖于时间戳的任务等,使用.PHONY定义伪目标的方法能够保证生成伪目标的依赖方法总是被执行的。
.PHONY可以让编译源文件时忽略掉源文件和可执行程序的修改时间对比,即不管如何都直接重新编译生成可执行文件。
假如我们目录中已经有一个 hello 可执行文件了,我们再次执行 make 命令想要重新编译生成一个新的 hello 可执行文件时,会发生错误:
显示 hello是最新的版本 。因为 hello 可执行文件的生成依赖于 main.c , makefile 会检查对比当前目录下的目标文件 hello 的最后修改时间和 main.c 的最后修改时间,发现 hello 的修改时间在 main.c 之后,证明hello已经是最新的了,不需要再进行重新编译的无用操作。当 main.c 被再次修改,也就是 main.c 修改时间在 hello 之后,再次执行 make 才能重新编译生成一个新的 hello 可执行文件。
而我们使用 .PHONY 将目标文件 hello 定义为伪目标,那么 make 就不会通过进行时间对比决定是否重新编译生成新的可执行文件,而是无论如何都会编译生成一个新的 hello 可执行文件。
将hello目标文件定义为伪目标:
也可以通过列表的方式一次定义多个伪目标。
保存退出,执行make指令:
正常来说不要给 hello 定义为 伪目标 ,这里只是演示一下。
变量
我们可以在开头定义一些 变量 ,并在下面的多条语句中使用。
这样当我们编译的源文件名不再是 main.c ,或者要生成的目标文件名不再是 hello 时,只需要把 Makefile 里的 变量 的值修改成别的值即可。这样使用 变量 来适应变化,减少了硬编码,提供了更高的灵活性。
通配符%的使用
例子:使用 makefile来 编译链接多个源文件来生成可执行程序,将 func.c 和 main.c 编译链接成可执行程序 add 。
fun.h func.c 以及 main.c的内容如下:
Makefile文件内容如下:
保存退出,运行make指令:
以上就是使用 makefile 来自动化编译生成可执行程序的方法。