Reputation: 11785
From all targets I have, I need one to run
the program.
From command line, I would state:
$ make main_run.err
or
$ make main_time.err
If it was specific to a certain program, I would write the rule:
main_run.err main_time.err: main.x
@echo ------------------- $(DEFSYM) Running ---------------------
/usr/bin/time -p -o main_time.err ./main.x > main_run.err || true
@echo -----------------------------------------------------------
Now, how to generalize it?
My first attempt was:
Command line:
$ make run main.x
And the rule:
run: $(filter-out $@,$(MAKECMDGOALS))
@echo --------------- $(DEFSYM) Running -----------------
/usr/bin/time -p -o time.err ./$< > run.err || true
@echo ---------------------------------------------------
This gave me some strange errors:
make: Circular run <- run dependency dropped.
------------- BUILD_150729_162018 Running -----------------
/usr/bin/time -p -o time.err ./main.x > run.err || true
-----------------------------------------------------------
make: 'main.x' is up to date.
My second and best attempt, the one I'm asking for help (unless there is another really easier way), is:
%_run.err %_time.err: %.x
@echo ------------------- $(DEFSYM) Running ---------------------
/usr/bin/time -p -o $@_time.err ./$< > $@_run.err || true
@echo -----------------------------------------------------------
This is almost ok! But filenames are wrong:
--------------- BUILD_150729_162239 Running -----------------
/usr/bin/time -p -o main_run.err_time.err ./main.x > main_run.err_run.err || true
-------------------------------------------------------------
And the command line is not good:
$ make main_run.err
I know I could use:
$ make run x=main
And define a variable $(x)
, but I prefer:
$ make run main.x
if possible.
Upvotes: 1
Views: 1280
Reputation: 81012
This attempt:
%_run.err %_time.err: %.x
@echo ------------------- $(DEFSYM) Running ---------------------
/usr/bin/time -p -o $@_time.err ./$< > $@_run.err || true
@echo -----------------------------------------------------------
Is exactly the right idea. You just need to adjust the automatic variables you are using to match the change to a pattern rule.
Specifically you want the $*
(stem) variable instead of the $@
(target) variable.
From the manual:
$@
The file name of the target of the rule. If the target is an archive member, then ‘$@’ is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ‘$@’ is the name of whichever target caused the rule’s recipe to be run.
$*
The stem with which an implicit rule matches (see How Patterns Match). If the target is dir/a.foo.b and the target pattern is a.%.b then the stem is dir/foo. The stem is useful for constructing names of related files.
In a static pattern rule, the stem is part of the file name that matched the ‘%’ in the target pattern.
So you end up with:
%_run.err %_time.err: %.x
@echo ------------------- $(DEFSYM) Running ---------------------
/usr/bin/time -p -o $*_time.err ./$< > $*_run.err || true
@echo -----------------------------------------------------------
The original original:
main_run.err main_time.err: main.x
@echo ------------------- $(DEFSYM) Running ---------------------
/usr/bin/time -p -o main_time.err ./main.x > main_run.err || true
@echo -----------------------------------------------------------
Was incorrect because it did not tell make that both files were created by a single run of the target so make might have run it twice if you specified both main_run.err
and main_time.err
at the same time. The pattern rule version does tell make about that fact (see the last paragraph of the manual section on Pattern Rule Examples for an explanation of that).
To make the initial command line a bit prettier you could add:
.PHONY: run_%
run_%: %_run.err %_time.err
Which will let you run make run_main
.
...
I say that but in a quick mock-up test that doesn't work and it needs to be:
.PHONY: run_%
run_%: %_run.err %_time.err ;
instead but I'm not at all sure why offhand.
Upvotes: 1