Makefile 配方更改时如何重建

Makefile 配方更改时如何重建,makefile,gnu-make,Makefile,Gnu Make,我想知道是否已经有人问过这个问题。搜索并不容易 make的设计假设Makefile有点像上帝。它完全了解项目的未来,除了添加新的源文件之外,不需要任何修改。这显然不是真的 我曾经让Makefile中的所有目标都依赖于Makefile本身。因此,如果我更改了Makefile中的任何内容,整个项目都将重建 这有两个主要限制: 它重建得太频繁了。添加链接器选项或新的源文件将重建所有内容 如果我在命令行上传递一个变量,比如makecflags=-O3,它将不会重建 我看到了一些正确的方法,但乍一看没有一

我想知道是否已经有人问过这个问题。搜索并不容易

make
的设计假设Makefile有点像上帝。它完全了解项目的未来,除了添加新的源文件之外,不需要任何修改。这显然不是真的

我曾经让Makefile中的所有目标都依赖于Makefile本身。因此,如果我更改了Makefile中的任何内容,整个项目都将重建

这有两个主要限制:

  • 它重建得太频繁了。添加链接器选项或新的源文件将重建所有内容
  • 如果我在命令行上传递一个变量,比如
    makecflags=-O3
    ,它将不会重建
  • 我看到了一些正确的方法,但乍一看没有一种是令人满意的

  • 使每个目标依赖于包含配方内容的文件
  • 将整个规则及其配方生成到一个文件中,该文件将包含在Makefile中
  • 有条件地向目标添加依赖项,以便在必要时强制重新生成它们
  • 使用该函数生成规则
  • 但所有这些解决方案都需要一种不同寻常的方法来编写配方。要么将整个规则作为字符串放在变量中,要么将配方包装在一个函数中,这会产生一些魔力

    我正在寻找的是一种解决方案,以尽可能简单的方式编写规则。尽可能少地增加垃圾。人们通常是如何做到这一点的?

    “make的设计假设Makefile有点像上帝。它完全了解项目的未来,除了添加新的源文件之外,不需要任何修改。”

    我不同意
    make
    是在这样一个时代设计的:源代码树位于一个分层的文件系统中,这是您需要了解的关于软件配置管理的所有知识,它将这个想法带到了逻辑的结果中,即所有这些都是一个文件(带有时间戳)。因此,将链接器选项、定位表、编译器标志和除厨房水槽之外的所有内容都放在一个文件中,并将其依赖项也放在一个文件中,就
    make
    而言,将产生一个一致、完整且无错误的构建环境

    这意味着必须通过文件命令行参数将数据传递给进程(也就是说,该进程依赖于该数据),因为make变量滥用了make的功能并导致错误的结果<代码>清理是系统性不当行为的技术补救措施。如果软件工程师正确地设计了make过程,就没有必要了

    问题是干净的构建过程很难设计和维护。但是:在现代软件过程中,瞬态/易失性构建参数(如
    使所有CFLAGS=O3
    无论如何都没有位置,因为它们破坏了配置管理的所有良好基础

    make
    唯一可以批评的可能是它不是软件构建的最终解决方案。我怀疑一个具有此任务的程序是否会达到
    make
    s受欢迎程度的1%

    TL;博士


    将编译器/链接器/定位器选项放在单独的文件中(位于一个中心、突出、易于维护和理解的逻辑位置),通过信息的粒度决定控制级别(例如,一个文件中的编译器标志,另一个文件中的链接器标志),并记录所有文件的真正相关性,瞧,您将拥有完全必要的编译量和正确的构建。

    我有针对多个平台编译的项目。在构建以前为不同体系结构编译的单个项目时,可以手动强制重建。但是,在为OpenWRT编译所有项目时,手动清理是不可管理的

    我的解决方案是创建一个标识平台的标记。如果丢失,所有内容都将重新编译

    ARCH ?= $(shell uname -m)
    CROSS ?= $(shell uname -s).$(ARCH)
    
    # marker for the last built architecture
    BUILT_MARKER := out/$(CROSS).built
    
    $(BUILT_MARKER) :
        @-rm -f out/*.built
        @touch $(BUILT_MARKER)
    
    build: $(BUILT_MARKER)
    # TODO: add your build commands here
    

    如果您的标志太长,您可以将其减少为校验和。

    我认为您无法获得比第一种方法更直接的结果,但没有一种方法是万无一失的:Make通常无法判断哪些更改会影响哪个目标。人们通常不会经常修改他们的makefile,从而使这种工作变得有价值。@Beta,我知道,在正确重建之前,我通常只花几分钟就意识到我需要
    清除
    。但我想也许有一个很好的方法让事情一劳永逸。永远。所以,基本上,“让我们再次使makefile保持静态”,哈?事实上,我认为make的瞬态参数是一种特性,而不是一种副作用滥用,我想完全支持它。这是一种测试各种编译器、链接器和选项的快速简便的方法。@Celelibi完全由您决定是否具有可控性、可跟踪性和基线功能。有些项目不需要这种开销,但大多数都需要。这种解决方案是否慢取决于(双关语)你的编辑工具,而不是方法。我宁愿在命令行文件中编辑,也不愿尝试恢复昨天的shell历史来再次找到开关,这使得难以找到的Heisen bug在上一次构建中重新出现。顺便说一句,yo要求“一劳永逸地解决问题”。正确使用
    make
    的规则是利用文件系统,而不是别的。如果你不喜欢这种哲学,
    make
    是错误的工具。