• 关于中型工程的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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    工作流程

    当在根目录执行 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

  • 相关阅读:
    【Java并发编程八】synchronized原理
    [Linux](7)环境变量
    【单片机项目实训】八路抢答器
    vue的diff算法
    Swoole v6 能否让 PHP 再次伟大?
    Java Heap Space问题解析与解决方案(InsCode AI 创作助手)
    在Transformers 中使用约束波束搜索引导文本生成
    语音分类入门案例: 英文数字音频分类
    [源码解析] TensorFlow 分布式之 MirroredStrategy 分发计算
    TRC肿瘤学丨艾美捷TRC癌症代谢研究领域
  • 原文地址:https://blog.csdn.net/nb_zsy/article/details/126847163