I have a project where I need to process many files in the same way. My GNUMakefile looks like this:
$(SOURCES) = file1.a file2.a file3.a ... fileN.a
$(TARGETS) = $(SOURCES:.a=.b)
%.b: %.a
build-tool $?
all: $(TARGETS)
This makefile executes build-tool
for each target, which is slow. So I want it to execute build-tool
only once with list of all updated prerequisites.
I tried to add the following rule:
$(TARGETS): $(SOURCES)
And it helped on first build like that:
$ make all
build-tool file1.a file2.a ... fileN.a
But on subsequent builds build-tool
was executed as many times as many targets I have:
$ touch file1.a && make all
build-tool file1.a
build-tool file1.a
...
build-tool file1.a
In the other hand, if I change recipe to build-tool $@
it will execute build-tool once with all prerequisites in all cases, which is undesirable too.
Is there some method to execute the recipe only once for all targets, i.e. with all prerequisites on first build and only modified on subsequent builds?
You can't use a pattern rule for this. That's why you're seeing everything build multiple times. You have to use a "sentinel" file that make can use to determine which files have changed since the last time you built.
For example, something like this will work:
$(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 $@
ETA: If you need another level you can do something like:
$(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 $@
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With