如何添加基于模式的依赖
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.out
和 file2.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
如果目标可以在子目录中,您可以使用 shell
make 函数调用 find
,而不是使用 wildcard
make 函数:
OUTFILES := $(shell find . -type f -name '*.out')
备注:
这仅适用于现有的 *.out
文件。如果目标文件列表不存在(因此可以通过 make 搜索)并且您没有在 makefile 中自己提供列表,则 Make 无法创建目标文件列表。
如果 source.txt
文件不包含 hello,world
字符串,您的 cat source.txt | grep "hello,world" > file1.out
配方将失败并返回非零退出状态。如果发生这种情况,make 将终止并显示一条错误消息。您可以通过以下方式避免这种情况:
cat source.txt | grep "hello,world" > file1.out || true
自动变量真的很方便。如果 source.txt
是您目标的唯一先决条件,您可以使用以下方法简化所有这些:
file1.out:
cat "$<" | grep "hello,world" > "$@" || true
file2.out:
cat "$<" > "$@"
($@
扩展为规则的目标,$<
扩展为第一个先决条件)。这避免了拼写错误并使食谱更通用。有时您甚至可以对多个目标使用相同的配方:
file1.out file3.out:
cat "$<" | grep "hello,world" > "$@" || true
我正在尝试向多个文件添加一个共同的依赖项。我已经通过模式匹配尝试过这个,但我无法让它工作。下面是我的最小可重现示例:
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.out
和 file2.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
如果目标可以在子目录中,您可以使用 shell
make 函数调用 find
,而不是使用 wildcard
make 函数:
OUTFILES := $(shell find . -type f -name '*.out')
备注:
这仅适用于现有的
*.out
文件。如果目标文件列表不存在(因此可以通过 make 搜索)并且您没有在 makefile 中自己提供列表,则 Make 无法创建目标文件列表。如果
source.txt
文件不包含hello,world
字符串,您的cat source.txt | grep "hello,world" > file1.out
配方将失败并返回非零退出状态。如果发生这种情况,make 将终止并显示一条错误消息。您可以通过以下方式避免这种情况:cat source.txt | grep "hello,world" > file1.out || true
自动变量真的很方便。如果
source.txt
是您目标的唯一先决条件,您可以使用以下方法简化所有这些:file1.out: cat "$<" | grep "hello,world" > "$@" || true file2.out: cat "$<" > "$@"
(
$@
扩展为规则的目标,$<
扩展为第一个先决条件)。这避免了拼写错误并使食谱更通用。有时您甚至可以对多个目标使用相同的配方:file1.out file3.out: cat "$<" | grep "hello,world" > "$@" || true