【问题标题】:Processing multiple files generated from single input处理从单个输入生成的多个文件
【发布时间】:2019-07-24 04:31:10
【问题描述】:

我有一个由脚本处理以生成多个输出文件的数据文件。然后进一步处理这些输出文件中的每一个。创建哪些文件取决于输入文件的内容,因此我无法明确列出它们。我不太清楚如何引用生成文件中生成的各种文件。

目前,我有这样的事情:

final.out: *.out2
  merge_files final.out $(sort $^)

%.out2: %.out1
  convert_files $?

%.out1: data.in
  extract_data data.in

No rule to make target '*.out2', needed by 'final.out' 失败。我认为这是因为 .out2 文件还不存在,因此通配符表达式没有按照我希望的方式替换。我曾尝试使用通配符函数,但失败了,因为先决条件列表最终为空。

任何指针将不胜感激。

【问题讨论】:

  • 当然,如果你能提前知道数据文件的名称,就把那个显式的列表放上去。

标签: makefile gnu-make


【解决方案1】:

编辑:修复了第二遍的先决条件列表。

在运行extract_data 命令之前,您显然无法计算中间文件列表。在这种情况下,解决方案在于运行两次 make。第一次生成*.out1 文件,第二次完成工作。您可以使用一个空的虚拟文件来标记是否 extract_data 命令是否再次运行:

ifeq ($(FIRST_PASS_DONE),)
final.out: .dummy
    $(MAKE) FIRST_PASS_DONE=yes

.dummy: data.in
    extract_data $<
else
OUT1 := $(wildcard *.out1)
OUT2 := $(patsubst %.out1,%.out2,$(OUT1))

final.out: $(OUT2)
    merge_files $@ $(sort $^)

%.out2: %.out1
    convert_files $?
endif

【讨论】:

  • 为什么要设置条件?为什么不直接说final.out: .dummy $(wildcard *.out2) 并取消变量?
  • 因为可能在第一次运行时*.out2 文件不存在并且$(wildcard *.out2) 的扩展将是空字符串...
  • 不过,您可以通过在该目标中运行辅助 make 来解决此问题。这将使用户不​​必理解和记住这个要求。
  • 这几乎可以工作。 *.out2 文件也有类似的问题,因为在运行 convert_files 之前它们可能不存在。
  • @PeterHumburg:你是对的,当然,我怎么能错过呢?我应该测试过。谢谢,我修正了我的答案。
【解决方案2】:

很遗憾,您的问题缺少一些细节,我会立即询问是否有 SW 开发人员会提交此 makefile 以供审核:

  • extract_files 是否提供文件列表?
  • convert_files 是转换一个文件还是多个文件?该示例似乎暗示它转换多个。
    • 那么我不得不质疑将提取、转换和合并为单独规则的决定,因为无论如何您都不会从并行构建中受益

以下是我会选择的方法。我将使用 tar 文件作为导致多个输出文件的输入文件的示例

  • 为已排序的文件列表生成生成文件片段
    • 使用tar 选项v 在提取文件时打印文件
    • 将每一行转换为makefile变量赋值
  • 包含定义$(DATA_FILES)的片段
    • 如果片段需要重新生成,make会在生成之后重新启动
  • 使用静态模式规则进行转换
  • 使用转换后的文件列表作为最终目标的依赖项
.PHONY: all
all: final.out

# extract files and created sorted list of files in $(DATA_FILES)
Makefile.data_files: data.tar
    set -o pipefail; tar xvf $< | sort | sed 's/^/DATA_FILES += /' >$@

DATA_FILES :=
include Makefile.data_files

CONVERTED_FILES := $(DATA_FILES:%.out1=%.out2)

$(CONVERTED_FILES): %.out2: %.out1
    convert_files $< >$@

final.out: $(CONVERTED_FILES)
    merge_files final.out $^

UPDATE 如果extract_data 没有提供文件列表,您可以像这样修改我的示例。但当然这取决于您的目录中没有与*.out1 匹配的其他文件。

# extract files and created sorted list of files in $(DATA_FILES)
Makefile.data_files: data.in
    set -o pipefail;   \
    extract_data $< && \
    (ls *.out1 | sort | sed 's/^/DATA_FILES += /') >$@

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 2022-01-02
    相关资源
    最近更新 更多