This is sort of a continuation of question from here. The problem is that there is a rule generating multiple outputs from a single input, and the command is time-consuming so we would prefer to avoid recomputation. Now there is an additional twist, that we want to keep files from being deleted as intermediate files, and rules involve wildcards to allow for parameters.
The solution suggested was that we set up the following rule:
file-a.out: program file.in
./program file.in file-a.out file-b.out file-c.out
file-b.out: file-a.out
@
file-c.out: file-b.out
@
Then, calling make file-c.out
creates both and we avoid issues with running make
in parallel with -j
switch. All fine so far.
The problem is the following. Because the above solution sets up a chain in the DAG, make
considers it differently; the files file-a.out
and file-b.out
are treated as intermediate files, and they by default get deleted as unnecessary as soon as file-c.out
is ready.
A way of avoiding that was mentioned somewhere here, and consists of adding file-a.out
and file-b.out
as dependencies of a target .SECONDARY
, which keeps them from being deleted. Unfortunately, this does not solve my case because my rules use wildcard patters; specifically, my rules look more like this:
file-a-%.out: program file.in
./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out
file-b-%.out: file-a-%.out
@
file-c-%.out: file-b-%.out
@
so that one can pass a parameter that gets included in the file name, for example by running
make file-c-12.out
The solution that make
documentation suggests is to add these as implicit rules to the list of dependencies of .PRECIOUS
, thus keeping these files from being deleted.
The solution with .PRECIOUS
works, but it also prevents these files from being deleted when a rule fails and files are incomplete. Is there any other way to make this work?
A hack to solve this is to define a target .SECONDARY
with no prerequisites, i.e.,
.SECONDARY:
which informs make
that all files should be treated as secondary and thus not removed, unless when make
gets interrupted or a rule fails. Unfortunately, this does not allow for selecting a subset of rules with wildcards to work this way, so I consider this only a hack (even though it's useful).
There can only be one recipe to be executed for a file. If more than one rule gives a recipe for the same file, make uses the last one given and prints an error message. (As a special case, if the file's name begins with a dot, no error message is printed.
File used by the GNU Make utility, a tool designed to build libraries and programs by executing source code, or makefiles; contains a list of commands that direct the shell it's running; other makefile extensions include . MAKEFILE and . MK; its commands are shell-specific, not universal.
all target is usually the first in the makefile, since if you just write make in command line, without specifying the target, it will build the first target. And you expect it to be all . all is usually also a . PHONY target.
The default goal is the target of the first rule in the first makefile. If the first rule has multiple targets, only the first target is taken as the default.
The Simplest Thing
file-a-%.out file-b-%.out file-c-%.out: program file.in
./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out
will do exactly what you want.
(Pattern rules with multiple targets are different than the normal rule with multiple targets that you were asking about here. See the bison example in the make manual.)
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