总之,针对这样一个中型大小的工程,我们可以将所有的构建规则都手动添加到顶层Makefile,让它做所有的事情,但是这样对于开发效率,代码增长与后期维护是一个巨大的挑战,所以我们提供这样一个’分布式’的Makefile模板供您参考。
首先我们推荐您阅读Example文件夹下的范例,并尝试使用各种规则,试着做一些改动,这将帮助您您理解当前的模板。
当您在使用这个模板时,您需要做的事情有:
如果一个工程的目录/源代码组织形式符合如下描述,那么我们称其为中型工程:
根文件夹: 包含主源文件(有 main() 的源文件)
Makefile: 顶层 Makefile
主源文件
源文件1
目录1
Makefile
源文件2
源文件3
子目录1
Makefile
源文件4
源文件5
目录2
Makefile
子目录2
Makefile
源文件6
源文件7
当在根目录执行 make 命令时,其首先查看 TARGET 指定的文件所依赖的所有文件是否都是最新的,而其依赖的 ALL_OBJS 是由规则 find-all-objs 来进行查找的。
如果 TARGET 任何依赖项不是最新的/还没有生成,则在其源文件所在目录生成对应的中间文件。待所有依赖都更新后,准备进行链接与编译。
在链接时,首先通过 find-all-objs 递归查找所有源文件所在目录下的中间文件,并将其统一链接、编译到一个目标文件中。由于在当前环境下每个中间文件都带有路径前缀,所以不同目录下的相同名称的源文件不会产生冲突(例如既存在 src1/f1.c 也存在 src2/f1.c 是可以的)
2.为什么要手动指定 DIRS 和 OBJS 变量,而不是自动查找
i:出于这样的考虑: 一些源代码文件并不需要/不应该生成中间文件来参与链接和编译,比如当前目录下模块的单元测试文件 unit_test.c ;一些目录并不包含任何源文件,比如只包含文档的目录 doc (虽然这些目录也可能包含一些源文件,但其都是说明性代码,并不应该用来参与编译)
ii:如果确实需要自动查找,那么可以通过如下方法实现
a.在文件 config/submake.global 中添加对于 DIRS 和 OBJS 的自动查找规则
b.将所有子文件夹中的 Makefile 中的手动指定的 DIRS 和 OBJS 变量去除
c.保持子文件夹中的 Makefile 引用文件 config/submake.global
iii:为了突出简洁性与通用性,我们这里不提供自动查找功能(其实在多数中型工程中,手动指定更加稳定且不易出错,反而是自动查找会导致一些隐藏的问题难以发现)
3.为什么不将所有规则放到 make.global 中,而是将一部分放在 submake.global 中:
因为子文件夹下的 all 规则和 clean 规则与根文件夹下有所不同,如果在 make.global 中添加这两个规则,会与根文件夹下的 Makefile 冲突,所以这里分成两个文件存放,但是引用时仅需引用 submake.global 即可,其中已经引用了 make.global 的所有内容
4.为什么重新构建时,即时所有的依赖文件都是最新的,TARGET 仍然会重新编译一遍
1.这个问题一般是由于 $(TARGET) 规则依赖了一些 PHONY 规则,这些规则不产生其名称对应的文件,所以有可能被认为总是过时的,需要重新执行并重新编译。目前来讲我们还没有更好的解决方案,只好容忍这一冗余的存在。不过如果您有更好地解决方案,还望不吝赐教,提出 issue 或者 pull-request 均是对本代码和其他人莫大的帮助。
资源链接:https://download.csdn.net/download/nb_zsy/86515214
转载自:https://github.com/TheNetAdmin/Makefile-Templates