关于中型工程的Makefile模板

我们定义的中型工程

  1. 可能会有多层嵌套的源代码文件夹
  2. 一个源代码文件夹下可能有多个源代码子文件夹
  3. 中间文件应当在其源文件所在目录生成,而不是同一生成到一个目录下(如统一生成到obj目录下)
  4. (大多数情况下)仅有一个目标需要生成

总之,针对这样一个中型大小的工程,我们可以将所有的构建规则都手动添加到顶层Makefile,让它做所有的事情,但是这样对于开发效率,代码增长与后期维护是一个巨大的挑战,所以我们提供这样一个’分布式’的Makefile模板供您参考。

如何使用

首先我们推荐您阅读Example文件夹下的范例,并尝试使用各种规则,试着做一些改动,这将帮助您您理解当前的模板。

当您在使用这个模板时,您需要做的事情有:

  1. 将 Template 目录下的 Makefile 文件复制到您的项目根文件夹
    i:填补标有 # FILL: … 的空白并删除这些注释
    ii:注意: 你需要手动在 DIRS 变量中指定所有含有源文件的子文件夹,在 OBJS 变量中指定所有当前目录下的中间目标文件
  2. 复制 Template 下的 config 目录到您的项目根文件夹
    i:在文件 config/make.global 中指定您需要用到的构建工具
    ii:在 Linux/Mac 系统下
    a. 由于 make 工具一般会在 PATH 环境变量中,所以可以删除 export MAKE := … 一行,这个变量存在的意义是在 PATH 失效或者是在 Windows 系统中 make 被脚本调用时会产生异常的目录查找的情况下,显式指定 make 工具路径,弥补一些系统层面的缺陷。
    iii.Under Windows
    a.填写 export MAKE := … 的空白部分并删除注释
  3. 在每一个包含源文件的子文件夹下添加 Makefile, 参照 Template/src/Makefile 或者 Example/…/Makefile 提供的示例(如果当前目录下没有源文件,但是当前目录的子文件夹中有源文件,则也需要添加一个Makefile到当前目录)
情景描述

如果一个工程的目录/源代码组织形式符合如下描述,那么我们称其为中型工程:

根文件夹: 包含主源文件(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 是可以的)

问题与讨论
  1. 为什么每个源文件夹都要有一个 Makefile:
    这样使我们能够在每个源文件所在的目录中维护其自己的中间文件,进一步允许了不同路径下的同名文件的存在。如果将所有中间文件输出到同一个目录下,那么目录1与目录2中的同名文件将生成同名的中间文件到指定目录下,这样会产生覆盖的问题,导致无法正常链接编译,只能额外添加规则或者进行重命名

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

举世无双勇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值