**Linux 知识补充 -- Makefile 文件的作用及编写方法** 1652270 **冯舜** Makefile 文件的作用 ================ *make* 是一个用于自动化编译、链接等操作的工程建构工具. `Makefile` 文件通常位于要编译的项目文件夹下, 在编译和链接的方式、顺序以及其他命令的执行顺序上, 它为 *make* 提供指导. Makefile 文件的基本语法 ================ Makefile 一般命名为 `Makefile` 或 `makefile`, 放在要构建的工程的根目录下. Makefile 的内容由一系列**规则**构成: ~~~~~~~~~~~~~~~~Makefile 目标 : 依赖 命令1 命令2 ... ~~~~~~~~~~~~~~~~ 除伪目标外 (伪目标需要定义为 `.PHONY` 这个特殊目标的依赖), 要用这个规则所生成的文件名来命名目标. 依赖可以同时是另一个目标. 此外, Makefile 还允许如 `变量名 = 值`、`$(变量名)`、`$(函数名 参数1[,参数2[...]])` 等语法, 用以定义、引用变量和调用参数. 在构建工程时, 若 `make` 后不加任何一个规则的目标名, 则表示构建第一个定义的规则的目标 "终极目标"; 在构建每个目标之前, 首先检查它的依赖是否满足 (文件是否存在). 若依赖的文件不存在或这个依赖是一个伪目标, 则需先生成依赖同名的目标. 当依赖满足, 则执行规则的命令, 来生成目标文件. Makefile 有 "隐含规则" 的概念, 其中包括 `.o` 文件在没有指定规则的情况下, 构建时会采用同名 `.c` 文件用 `cc` 编译; 及可执行文件构建时会默认采用同名 `.o` 文件用 `ld` 链接. 几种情况的 Makefile 写法 ================ ## 建立目录 在 `~/3/`下建立子目录, 如//mkdir//. !![mkdir,建立几个子目录] ## 在 01 下建立源文件和 Makefile 如//vimcs//, 建立三个 `.c` 源代码文件. !![vimcs,建立源文件] 建立后, 如//makefile//, 建立 Makefile 文件. !![makefile,建立 Makefile] 建立后, 尝试运行 `make`, 构建成功; 接着运行 `./test` 尝试运行可执行文件, 执行成功, 如//makenrun//. !![makenrun,构建和运行成功] 发现在源程序文件中忘记加换行, 因此修改前两个 `.c` 文件如//modify//, 并重新 `make` 运行, 如//remake//. 根据输出, 可知仅前两个 `.c` 文件被重新编译为 `.o`, 且重新运行可执行文件输出正确, 符合预期. !![modify,修改源程序文件] !![remake,重新构建运行] 运行 `make clean`, 发现所有的 object 文件和可执行文件均被删除, 符合预期, 如//clean//. !![clean,清理工程] ## 在 02 下建立源文件和 Makefile 如//02codes//, 建立三个 `.c` 源代码文件和一个 `.h` 头文件. !![02codes,建立源文件] 建立后, 如//02makefile//, 建立 Makefile 文件. 其中, 三个 `.o` 文件添加上了对 `test.h` 的依赖, 但命令留空, 意味着采用隐含规则生成. !![02makefile,建立 Makefile] 建立后, 尝试运行 `make`, 构建成功; 接着运行 `./test` 尝试运行可执行文件, 执行成功, 如//02make//. !![02make,构建和运行成功] 修改 `test.h` 文件的预处理器宏 `a` 为 `20`, 并重新 `make` 运行, 如//02remake//. 根据输出, 可知三个 `.c` 文件都被重新编译为 `.o`, 且重新运行可执行文件输出正确, 符合预期. !![02remake,重新构建运行] 运行 `make clean`, 发现所有的 object 文件和可执行文件均被删除, 符合预期, 如//02clean//. !![02clean,清理工程] ## 在 03 下建立源文件和 Makefile 如//03files//, 建立三个 `.c` 源代码文件, 和一个 `Makefile` 文件. 在 `Makefile` 中, 记录所有可执行文件的 `run` 变量从记录所有 object 文件的 `obj` 变量替换而来, 且它们的规则用模式和静态规则合为一条, 便于以后增加和修改 (只需动 `obj` 变量). !![03files,建立源文件和 `Makefile`] 建立后, 尝试运行 `make`, 构建成功; 接着运行 `./test1` 等可执行文件, 执行成功. 再运行 `make clean`, 清理工程成功, 如//03make//. !![03make,构建、运行和清理成功] 执行 `make` 时分别加 `test1` 和 `test3` 参数, 作为终极目标, 从输出看出只分别构建了它们所需的文件, 没有构建 `test2` 相关文件, 符合预期, 如//03makeone//. !![03makeone,构建其他的目标] ## 在上级目录下建立 Makefile 如//rootmakefile//, 在前述三个文件夹的上级目录建立一个 `Makefile` 文件. 在 `Makefile` 中, 本目录下所有子目录的列表用 `wildcard` 和 `dir` 函数, 扩展通配符再筛选出来. 另外还建立了各个子目录的建构目标和清理目标, `$(dirs)` 和 `$(dirsclean)`, 均指定为伪目标. `all` 终极目标依赖所有子目录建构目标, `clean` 目标依赖所有子目录清理目标. !![rootmakefile,建立上级目录 `Makefile`] 建立后, 尝试运行 `make`, 从输出提示看来, 进入各个子目录构建成功, 如//rootmake//. 再运行 `make clean`, 清理工程成功, 如//rootclean//. !![rootmake,上级目录下 `make`] !![rootclean,上级目录下 `make clean`] 修改 `01` 和 `02` 目录的名称为 `x01` 和 `x02`, 重新运行 `make` 和 `clean`, 均执行成功, 如//rootaltername//和//rootalternameclean//. !![rootaltername,修改目录名后 `make`] !![rootalternameclean,修改目录名后 `make clean`] ### 关于 Makefile 文件换名 Makefile 文件换名后, 只需在执行 `make` 时增加参数 `-f 文件名` 即可. 如 `Makefile` 更名为 `mymake`, 执行时命令为 `make -f mymake` 即可.