makefile - Makefiles是如何重新制作的——看不懂官方文档

标签 makefile gnu

我无法理解官方 gmake 文档的第 3 章(从第 3.5 节开始)

https://www.gnu.org/software/make/manual/make.html#Remaking-Makefiles

文档说: ...读入所有 makefile 后,make 会将每个 makefile 视为目标并尝试更新它。如果 makefile 有一条规则说明如何更新它....,它将在必要时进行更新。检查完所有 makefile 后,如果确实有任何更改,make 将从头开始并重新读取所有 makefile。 (它还会尝试再次更新它们中的每一个,但通常这不会再次更改它们,因为它们已经是最新的。)每次重新启动都会导致特殊变量 MAKE_RESTARTS 被更新。

所以我尝试使用这个 mkfile(G.M. 建议的 -include 的存在不会改变任何内容):

all:
        echo all $(MAKE_RESTARTS) aaa

#-include: mkfile

mkfile:
        echo touch
        touch mkfile

我希望 mkfile 第一次运行后 mkfile 修改时间发生变化,并且 make 必须一次又一次地运行它。 但什么也没发生:

$ make -f  mkfile 
echo all  aaa
all aaa
$

此外,目标“mkfile”未按照文档中的预期进行调用:读入所有 makefile 后,make 会将每个文件视为目标并尝试更新它。

我有什么误解吗?您能否举例说明文档中“重新制作”makefile 的含义?

UPD:我尝试过 Andreas 的建议,但再次得到了奇怪的结果:

  1. 原始 mkfile 但使用 --always-make 运行
 $ make --always-make -f mkfile 
echo touch
touch
touch mkfile
echo all 1 aaa
all 1 aaa

此处目标“mkfile”运行一次,目标“all”也运行一次。结果运行的结果是可重复的。

  • 如果我更改目标“mkfile”以强制运行,结果会很奇怪,并且调用之间会有所不同: MK文件:
  • all:
        echo all $(MAKE_RESTARTS) aaa
    
    mkfile: force
        echo touch
        touch mkfile
    
    force: ; 
    

    结果:

    $ make -f mkfile 
    echo touch
    touch
    touch mkfile
    echo touch
    touch
    touch mkfile
    echo touch
    touch
    touch mkfile
    ................
    touch mkfile
    echo touch
    touch
    touch mkfile
    echo all 16 aaa
    all 16 aaa
    $ make -f mkfile 
    echo touch
    touch
    touch mkfile
    echo touch
    touch
    touch mkfile
    echo touch
    touch
    touch mkfile
    echo all 2 aaa
    all 2 aaa
    
    $ make -f mkfile
    echo touch
    touch
    touch mkfile
    ...............
    touch mkfile
    echo all 13 aaa
    all 13 aaa
    $
    

    UPD2 - 关于 MAKE_RESTARTS

    --always-make 仅当 makefile 的目标没有先决条件时才遵循 MAKE_RESTARTS。

    mk文件:

    all:
        echo all $(MAKE_RESTARTS) aaa
    
    mkfile:
        echo touch $(MAKE_RESTARTS)
        sleep 0.5
        touch mkfile
    

    结果:

    $ make --always-make -f  mkfile
    echo touch 
    touch
    sleep 0.5
    touch mkfile
    echo all 1 aaa
    all 1 aaa
    $
    

    如果makefile的目标有强制先决条件,则循环是无限的(我什至尝试强制将MAKE_RESTARTS设置为大于0的值)

    mk文件:

    MAKE_RESTARTS := 1
    
    all:
        echo all $(MAKE_RESTARTS) aaa
    
    mkfile: force
        echo touch $(MAKE_RESTARTS)
        sleep 0.5
        touch mkfile
    
    force: ; 
    
    

    结果:

    $ make --always-make -f  mkfile
    echo touch 1
    touch 1
    sleep 0.5
    touch mkfile
    echo touch 1
    touch 1
    sleep 0.5
    touch mkfile
    echo touch 1
    touch 1
    sleep 0.5
    touch mkfile
    ^C
    

    最佳答案

    为此:

    all:
            echo all $(MAKE_RESTARTS) aaa
    mkfile:
            echo touch
            touch mkfile
    

    make -f mkfile运行时,它会尝试构建mkfile。 make 手册说,如果一个目标没有先决条件,那么如果它存在,它就被认为是最新的(当它不依赖任何东西时,它怎么会过时呢?) > 文件存在(显然),这条规则实际上是一个空操作。如果您想查看重建 makefile 的行为,那么 makefile 必须有一些先决条件,表明它已过时。

    如果您使用 --always-make 运行它,您将遇到 this statement在 GNU make 手册中:

    GNU make proceeds to consider targets and their prerequisites using the normal algorithms; however, all targets so considered are always remade regardless of the status of their prerequisites. To avoid infinite recursion, if MAKE_RESTARTS is set to a number greater than 0 this option is disabled when considering whether to remake makefiles.

    (强调已添加)。

    如果您使用 force 目标运行,那么它将如您所见进行更新。对于某些操作系统,这将永远运行。然而,对于其他人来说,在某些时候,touch 命令的运行速度足够快,以至于它实际上不会更改 mkfile 文件的修改时间;它会非常快,以至于命令运行之前和之后的修改时间将相同。当配方运行但不更改该目标的修改时间时,则该目标不会被视为已修改,并且依赖于它的任何规则都不会因为该目标而被视为过时。

    当发生这种情况时,make 认为目标没有更改,并且不再重新执行自身。

    关于makefile - Makefiles是如何重新制作的——看不懂官方文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65058553/

    相关文章:

    c - 在 C 源代码中使用 GNU 版本的 basename() 和 dirname()

    makefile - 如何检测是否设置了 makefile `--silent/--quiet` 命令行选项?

    使用eclipse进行C编程

    c++ - 我如何使用 make 来维护一个通用的 C++ 头文件包含目录?

    gnu - Make distcheck 不会复制所有来源

    Makefile顺序执行

    c - 为什么需要缓存内存对齐?

    linux - 在 GNU/Linux 上在哪里保存配置/数据文件?

    shell - 如何比较Makefile中的两个shell命令输出?

    linux - 目标有一个依赖项,该依赖项本身不是目标