Reputation: 1696
Let's say I have this minimalist main.c program
int main(void)
{
return 0;
}
and this Makefile
.PHONY: %.run
%.run: %
./$<
If I run the following command
make main.run
which, I expect, would
make
default implicit %: %.c
rule)But what I get instead is the following error
make: *** No rule to make target 'main.run'. Stop.
I tried to disable default implicit rules and set my own compile rule with
.SUFFIXES:
%: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $<
but this doesn't help.
However, in both cases, if I run make main
first, then make main.run
, it is working as expected. But running two commands is exactly what I am trying to avoid with my %.run
rule.
Of course if I replace my pattern rule with this explicit rule
main.run: main
./main
it is working.
Also, if I change my pattern rules to %.x: %.c
and %.run: %.x
with a .x suffix for the executables, this is working, but again I don't want suffixes.
Of course, my question is not to know if this is the right way to compile and run a program in one command, it is really to know why this Makefile does not execute the way I am expecting.
Upvotes: 4
Views: 1425
Reputation: 9962
It would appear the restrictions of the Match Anything Rules for targets also apply to prerequisites, although I can not find this stated anywhere1.
If the executable main
already exists, the OP's makefile:
%.run: %
./$<
works perfectly fine. Two ways to fix the problem are to:
main
, ormain
; this will cause main
to be built by the implicit pattern-matching rules, or an explicit rule.We give four solutions.
1. The following makefile works (tested on GNU make):
%.run: %
./$<
main:
Here the word main
is hard-coded in the makefile. You could handle adhoc targets via:
RUN_TARGETS = main.run foo.run bar.run $(filter %.run,$(MAKECMDGOALS))
%.run: %
./$<
$(RUN_TARGETS:.run=) dummy:
(We need filter
to ensure that a typo such as make claen
returns an error message. dummy
is used to avoid an empty target list.)
2. Another variation is to use a Static Pattern Rule, which seems to bypass this bug/feature:
RUN_TARGETS = main.run foo.run bar.run $(filter %.run,$(MAKECMDGOALS))
$(RUN_TARGETS) dummy.run: %.run: %
./$<
3. And yet another way is to use a terminal match-anything rule, if all your executables can be built from a single C file, as per the built-in rules. This also deletes main
after running, for whatever reason:
%.run: %
./$<
%:: %.c # note double-colon, for terminal match-anything rule
cc $< -o $@
4. Finally, a completely different way to resolve the problem is to handle the prerequisite explicitly by invoking make recursively:
%.run:
make $*
./$*
For somewhat-related questions, see GNU make seems to ignore non-terminal match-anything rules for intermediate files and Force make to use a more specific rule. Note that putting main
as prerequisite to an unrelated rule, such as:
%.run: %
./$<
garbage: main
does not seem to work.
1 But see perhaps Makefile match anything rule as intermediate.
Upvotes: 1