如何添加基于模式的依赖

时间:2018-06-27 12:36:47

标签: makefile gnu-make

我正在尝试向多个文件添加公共依赖项。我已经通过模式匹配尝试了此操作,但无法正常工作。下面是我的可复制性最低的示例:

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文件)的依赖项。任何建议都将不胜感激(如果这是一个基本问题,我深表歉意,但我在制造手册中找不到任何相关内容。

1 个答案:

答案 0 :(得分:3)

我假设您正在使用GNU make。您的问题来自GNU make如何处理模式(隐式)规则。从Implicit Rule Search AlgorithmGNU make manual部分开始介绍:

  

以下是用于搜索隐式规则的过程   目标t每个双冒号规则都遵循此过程,   没有配方,对于普通规则的每个目标都没有一个   配方,以及不是任何规则目标的每个先决条件。   还递归地遵循了来自的先决条件   隐式规则,用于搜索规则链。

因此,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

如果目标可以位于子目录中,则可以使用shell make函数来调用find,而不要使用wildcard make函数:

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

注意:

  1. 这仅适用于现有的*.out文件。如果目标文件列表尚不存在(因此可以通过make进行搜索),并且您自己没有在makefile中提供该列表,则make不会发明目标文件的列表。

  2. 如果cat source.txt | grep "hello,world" > file1.out文件不包含source.txt字符串,则您的hello,world配方将失败,退出状态为非零。如果发生这种情况,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