如何添加基于模式的依赖

How to add pattern based dependency

我正在尝试向多个文件添加一个共同的依赖项。我已经通过模式匹配尝试过这个,但我无法让它工作。下面是我的最小可重现示例:

file1.out:
    cat source.txt | grep "hello,world" > file1.out

file2.out:
   cat source.txt > file2.out

%.out: source.txt

我的目标是将 source.txt 添加为 file1.out 和 file2.out 的依赖项(以及我稍后可能添加的所有其他 *.out 文件)。任何建议将不胜感激(如果这是一个基本问题,我深表歉意,但我在制作手册中找不到任何相关内容。

我假设您使用的是 GNU make。您的问题来自 GNU make 如何处理模式(隐式)规则。来自Implicit Rule Search Algorithm of the GNU make manual节的介绍:

Here is the procedure make uses for searching for an implicit rule for a target t. This procedure is followed for each double-colon rule with no recipe, for each target of ordinary rules none of which have a recipe, and for each prerequisite that is not the target of any rule. It is also followed recursively for prerequisites that come from implicit rules, in the search for a chain of rules.

因此,file1.outfile2.out 目标不考虑您的模式规则,因为它们是普通规则的目标 具有配方

解决方案:您可以在变量中列出 *.out 目标并使用它来声明它们都依赖于 source.txt:

OUTFILES := $(wildcard *.out)

$(OUTFILES): source.txt

file1.out:
    cat source.txt | grep "hello,world" > file1.out

file2.out:
    cat source.txt > file2.out

如果目标可以在子目录中,您可以使用 shellmake 函数调用 find,而不是使用 wildcard make 函数:

OUTFILES := $(shell find . -type f -name '*.out')

备注:

  1. 这仅适用于现有的 *.out 文件。如果目标文件列表不存在(因此可以通过 make 搜索)并且您没有在 makefile 中自己提供列表,则 Make 无法创建目标文件列表。

  2. 如果 source.txt 文件不包含 hello,world 字符串,您的 cat source.txt | grep "hello,world" > file1.out 配方将失败并返回非零退出状态。如果发生这种情况,make 将终止并显示一条错误消息。您可以通过以下方式避免这种情况:

    cat source.txt | grep "hello,world" > file1.out || true
    
  3. 自动变量真的很方便。如果 source.txt 是您目标的唯一先决条件,您可以使用以下方法简化所有这些:

    file1.out:
        cat "$<" | grep "hello,world" > "$@" || true
    
    file2.out:
        cat "$<" > "$@"
    

    $@ 扩展为规则的目标,$< 扩展为第一个先决条件)。这避免了拼写错误并使食谱更通用。有时您甚至可以对多个目标使用相同的配方:

    file1.out file3.out:
        cat "$<" | grep "hello,world" > "$@" || true