一次为多个目标执行配方

ins*_*per 5 makefile gnu-make

我有一个项目,我需要以相同的方式处理许多文件。我的 GNUMakefile 看起来像这样:

$(SOURCES) = file1.a file2.a file3.a ... fileN.a
$(TARGETS) = $(SOURCES:.a=.b)

%.b: %.a
    build-tool $?

all: $(TARGETS)
Run Code Online (Sandbox Code Playgroud)

这个 makefilebuild-tool为每个目标执行,这很慢。所以我希望它只执行build-tool一次并列出所有更新的先决条件。
我尝试添加以下规则:

$(TARGETS): $(SOURCES)
Run Code Online (Sandbox Code Playgroud)

它有助于第一次构建这样的:

$ make all
build-tool file1.a file2.a ... fileN.a
Run Code Online (Sandbox Code Playgroud)

但是在随后的构建build-tool中执行的次数与我拥有的目标一样多:

$ touch file1.a && make all
build-tool file1.a
build-tool file1.a
...
build-tool file1.a
Run Code Online (Sandbox Code Playgroud)

另一方面,如果我将 recipe 更改为build-tool $@它会在所有情况下使用所有先决条件执行一次 build-tool,这也是不可取的。
是否有一些方法可以为所有目标只执行一次配方,即在第一次构建时使用所有先决条件,并且只在后续构建中修改?

Mad*_*ist 5

您不能为此使用模式规则。这就是为什么您会看到所有内容都多次构建。您必须使用 make 可以用来确定自上次构建以来哪些文件发生了更改的“哨兵”文件。

例如,这样的事情会起作用:

$(SOURCES) = file1.a file2.a file3.a ... fileN.a
$(TARGETS) = $(SOURCES:.a=.b)

.PHONY: all
all: .ran-build-tool

.ran-build-tool: $(SOURCES)
        build-tool $?
        @touch $@
Run Code Online (Sandbox Code Playgroud)

ETA:如果您需要另一个级别,您可以执行以下操作:

$(SOURCES) = file1.a file2.a file3.a ... fileN.a
$(TARGETS) = $(SOURCES:.a=.b)

.PHONY: all
all: .ran-build-tool2

.ran-build-tool2: $(TARGETS) | .ran-build-tool
        build-tool2 $?
        @touch $@

.ran-build-tool: $(SOURCES)
        build-tool $?
        @touch $@
Run Code Online (Sandbox Code Playgroud)