Make 不能识别间接依赖的变化

Make doesn't recognize changes in indirect dependencies

考虑这个简单的 makefile:

all: output.txt

# The actual build command won't be this simple.
# It'll more be like "some-compiler file1.txt",
# which includes file2.txt automatically.
output.txt: file1.txt
    cat file1.txt file2.txt > output.txt

file2.txt:
    echo "heyo" > file2.txt

file1.txt: file2.txt

首先 运行,Make 识别出 file2.txtfile1.txt 的依赖项,因此需要为要构建的 output.txt 构建它。因此,它 运行s echo "heyo" > file2.txt 然后 cat file1.txt file2.txt > output.txt.

但是,在随后的 运行 中,如果 file2.txt 发生更改,Make 不会重建 !如果 file1.txt 改变了,它会改变,但 file2.txt 不会改变。它只是给出了可怕的 make: Nothing to be done for 'all'. 消息。

我看到人们建议的一个 hacky 解决方案是执行以下操作:

all: output.txt

output.txt: file1.txt file2.txt
    cat file1.txt file2.txt > output.txt

但是,这对我来说是不可能的,因为我的次要依赖项(像 file1.txt: file2.txt 这样的行)是使用 include.

动态生成的

当我有多级依赖关系时,如何确保 Make 检查修改一直向上? 23=]

您的 makefile 既不生成也不更新 file1.txt(即:file1.txt 必须存在于 运行 make).它包含 没有用于从 file2.txt 生成 file1.txt 的配方。它只有一个空规则(即:一个没有配方的规则):

file1.txt: file2.txt

因为 file1.txtoutput.txt 的先决条件,这个空规则只是暗示 file2.txt 必须存在才能构建 output.txt,它甚至不更新 file1.txt 当生成 file2.txt 时。

由于 file1.txtoutput.txt 的唯一先决条件,并且 file1.txt 永远不会被 make 更新,一旦 output.txt 生成,它始终保持 up-to-date(前提是file1.txt没有被外部更新)。

file2.txt 被更改永远不会导致 output.txt 被重建,因为:

  • 它不是 output.txt 的先决条件。
  • 它不会更新 file1.txt(这是 output.txt 的唯一先决条件)。

解决方案

根据您当前的 output.txt 规则:

output.txt: file1.txt
    cat file1.txt file2.txt > output.txt

如果你想在每次file2.txt变化时构建output.txt,那么你需要在每次file2.txt变化时构建file1.txt。这可以通过 recipe 实际上更新 file1.txt 并以 file2.txt 作为先决条件的规则来实现,例如:

file1.txt: file2.txt
    touch $@

我认为这里的问题是您的 makefile 稍微简单了。

a -> b 表示 a depends on b。从你的 makefile 你有...

output.txt -> file1.txt -> file2.txt

make 尝试更新 output.txt 时,它发现 output.txt 依赖于 file1.txt。然后它注意到 file1.txt 依赖于 file2.txt。那时依赖链停止。如果 make 发现 file2.txtfile1.txt 更新,它将 运行 与 file1.txt: file2.txt 延迟关联的命令。然而,在这种情况下,没有任何命令——只有依赖项本身。这很好,但这确实意味着即使 file2.txt 更新 file1.txt 也不会。因此,当 make 在依赖链上移动到...

output.txt: file1.txt

它发现 output.txt 仍然file1.txt 更新,因此不需要 运行 与该依赖项关联的任何命令。

如果添加 touch 命令...

file1.txt: file2.txt
        touch $@

然后 file1.txt 更新,因此依赖链按您预期的方式工作。