在 Makefile 中使用 `subst` 函数匹配依赖项
Matching a dependency using `subst` function in Makefile
我有一个目标规则
data/processed/21.12.2021/experiment6/written_piv21122021.005.exp6.mp4
在我的 makefile 中使其具有依赖性
data/raw/21.12.2021/experiment6/piv21122021.005.exp6.mov
使用 subst
函数,我正在尝试通过模式匹配创建依赖关系
%/written_*.mp4: \
$(subst processed,raw, $$*)/*.mov \
<do something>
但是,上述规则无法找到*.mov 依赖项。我已经尝试了很多版本的 $(subst processed,raw, $$*)/*.mov
来匹配依赖但没有用。
如何做到这一点?正确的语法是什么?
首先,你不能这样做:
%/written_*.mp4:
您不能将模式 %
与通配符 *
结合使用。您必须意识到 make 的工作分为两个非常独立的步骤:首先,解析所有 makefile 并将所有目标和先决条件的内部表示构建到一个图中。然后,遍历该图,弄清楚需要构建什么以及如何构建它,以及 运行 食谱。
在解析 makefile 时(在第一步中)扩展目标和先决条件中的 Make 变量、函数和通配符。像 $*
这样的自动变量在调用配方(第二步)之前不会被设置,而像 %
这样的模式在 make 尝试决定如何构建某些东西之前不会 matched/expanded (再次在第二步)。
所以,规则如下:
%/written_*.mp4: $(subst processed,raw, $$*)/*.mov
无法工作,因为通配符将扩展为与文字文件名 %/written_*.mp4
相匹配的文件,但显然没有匹配项,因为您没有名为 %
的目录。在任何情况下,你都不能在 targets 中使用通配符,因为当 make 解析 makefile 时,这些目标将不存在(因为这是你想要构建的目标)所以通配符不会匹配任何东西。此外,$$*
是文字字符串 $*
并且其中没有 processed
字符串,因此 subst
函数将不执行任何操作。而且,即使 /*.mov
确实匹配了某些东西,它也会将所有匹配该通配符的文件作为 每个 目标的先决条件,这样只要任何一个改变,它们就会全部重建。
最后,你绝对不应该在你的先决条件之后使用反斜杠:这只会把你的食谱变成先决条件。
您的问题很难解决,因为您的目标和先决条件在多个不同的地方不同,并且 make 不支持多个 %
匹配。您可以通过以下方式完成大部分工作:
data/processed/%.mp4: data/raw/%.mov
<do something>
然而这并不完全正确,因为目标中的 %
是 written_...
而在先决条件中它只是 ...
而这在 make 中是不可能表示的。
如果您可以修改文件名,以便您可以使用 piv21122021.005.exp6.written.mp4
而不是 written_piv21122021.005.exp6.mp4
(或者更好的是您根本不需要 written_
前缀),那么您可以轻松做到这一点。如果不是,你需要非常喜欢才能完成这项工作。
这是一个不完美的拼凑。
将工作委托给另一个 makefile,我称之为 adjunct.mk
。在主生成文件中:
data/processed/%.mp4:
@$(MAKE) -f adjunct.mk $@
并且在 adjunct.mk
这个丑陋的转变中:
.SECONDEXPANSION:
$(MAKECMDGOALS): $$(patsubst data/processed/%,data/raw/%,$$(subst written_,,$$(patsubst %.mp4,%.mov,$$@)))
...do whatever with $< and $@...
这会招致递归 Make 的通常成本:它使 higher-level Make 对较低层跟踪的依赖关系视而不见。因此,如果您的 Make 必须构建那个 mov
文件,或者您在 mov
不存在时尝试构建 mp4
,那么此解决方案将需要更仔细的管道安装才能正常工作.
我有一个目标规则
data/processed/21.12.2021/experiment6/written_piv21122021.005.exp6.mp4
在我的 makefile 中使其具有依赖性
data/raw/21.12.2021/experiment6/piv21122021.005.exp6.mov
使用 subst
函数,我正在尝试通过模式匹配创建依赖关系
%/written_*.mp4: \
$(subst processed,raw, $$*)/*.mov \
<do something>
但是,上述规则无法找到*.mov 依赖项。我已经尝试了很多版本的 $(subst processed,raw, $$*)/*.mov
来匹配依赖但没有用。
如何做到这一点?正确的语法是什么?
首先,你不能这样做:
%/written_*.mp4:
您不能将模式 %
与通配符 *
结合使用。您必须意识到 make 的工作分为两个非常独立的步骤:首先,解析所有 makefile 并将所有目标和先决条件的内部表示构建到一个图中。然后,遍历该图,弄清楚需要构建什么以及如何构建它,以及 运行 食谱。
在解析 makefile 时(在第一步中)扩展目标和先决条件中的 Make 变量、函数和通配符。像 $*
这样的自动变量在调用配方(第二步)之前不会被设置,而像 %
这样的模式在 make 尝试决定如何构建某些东西之前不会 matched/expanded (再次在第二步)。
所以,规则如下:
%/written_*.mp4: $(subst processed,raw, $$*)/*.mov
无法工作,因为通配符将扩展为与文字文件名 %/written_*.mp4
相匹配的文件,但显然没有匹配项,因为您没有名为 %
的目录。在任何情况下,你都不能在 targets 中使用通配符,因为当 make 解析 makefile 时,这些目标将不存在(因为这是你想要构建的目标)所以通配符不会匹配任何东西。此外,$$*
是文字字符串 $*
并且其中没有 processed
字符串,因此 subst
函数将不执行任何操作。而且,即使 /*.mov
确实匹配了某些东西,它也会将所有匹配该通配符的文件作为 每个 目标的先决条件,这样只要任何一个改变,它们就会全部重建。
最后,你绝对不应该在你的先决条件之后使用反斜杠:这只会把你的食谱变成先决条件。
您的问题很难解决,因为您的目标和先决条件在多个不同的地方不同,并且 make 不支持多个 %
匹配。您可以通过以下方式完成大部分工作:
data/processed/%.mp4: data/raw/%.mov
<do something>
然而这并不完全正确,因为目标中的 %
是 written_...
而在先决条件中它只是 ...
而这在 make 中是不可能表示的。
如果您可以修改文件名,以便您可以使用 piv21122021.005.exp6.written.mp4
而不是 written_piv21122021.005.exp6.mp4
(或者更好的是您根本不需要 written_
前缀),那么您可以轻松做到这一点。如果不是,你需要非常喜欢才能完成这项工作。
这是一个不完美的拼凑。
将工作委托给另一个 makefile,我称之为 adjunct.mk
。在主生成文件中:
data/processed/%.mp4:
@$(MAKE) -f adjunct.mk $@
并且在 adjunct.mk
这个丑陋的转变中:
.SECONDEXPANSION:
$(MAKECMDGOALS): $$(patsubst data/processed/%,data/raw/%,$$(subst written_,,$$(patsubst %.mp4,%.mov,$$@)))
...do whatever with $< and $@...
这会招致递归 Make 的通常成本:它使 higher-level Make 对较低层跟踪的依赖关系视而不见。因此,如果您的 Make 必须构建那个 mov
文件,或者您在 mov
不存在时尝试构建 mp4
,那么此解决方案将需要更仔细的管道安装才能正常工作.