Can't change .PHONY target's prerequisite name in GNU Makefile - makefile

Can someone please explain why
running make clean
prints
Target clean
with below makefile
.PHONY: all
all: clean
clean:
echo "Target clean"
But running
make clean_local
throws exception
No rule to make target 'clean_local'
when I change makefile to
.PHONY: all
all: clean_local
clean_local:
echo "Target clean_local"

Related

Impose an order for the prerequisites of a target

I have a makefile snippet:
all: $(objects)
fresh: clean all
clean: ;rm $(objects)
Here, I want to ensure that when I do make fresh - clean should precede all.
But how can I make sure this, given that when I do make all, clean should not be made?
I can imagine that one way could be like this
fresh: clean
make all
Is it the right (or the only) way to solve this issue?
If you use GNU make:
all:
#echo $#
#sleep 1
#echo end $#
clean:
#echo $#
#sleep 1
#echo end $#
fresh:: clean
fresh:: all
.PHONY: clean fresh all
Please note the double colon after targets fresh! See the documentation:
The double-colon rules for a target are executed in the order they
appear in the makefile.
If you run make -j2 fresh it shows it works as expect:
clean
end clean
all
end all
But with fresh:: clean all doesn't work properly parallel (maybe unexpected).
With BSD make:
all:
#echo $#
#sleep 1
#echo end $#
clean:
#echo $#
#sleep 1
#echo end $#
fresh: clean all
#echo $#
.ORDER: clean all
.PHONY: clean all fresh
Note the line begin with .ORDER. It works well in parallelization too (see man make). Without parallelization the order of dependencies in line fresh: counts.
As you already suggest in your question, calling make recursively on the same makefile for the target all in a recipe whose prerequisite is clean:
# At the very beginning of the makefile
CURRENT_MAKEFILE := $(lastword $(MAKEFILE_LIST))
# ...
.PHONY: fresh
fresh: clean
$(MAKE) -f $(CURRENT_MAKEFILE) all
This imposes an order, since the target fresh depends on the prerequisite clean, clean's recipe will be executed before fresh's recipe, which in turn will execute all's recipe.
Note that I'm using here $(MAKE) instead of make for the recursion.

Specify all Makefile targets as .PHONY with wildcard

All targets in my Makefile aren't real files, is it valid to specify just .PHONY: %. Or should I list all targets?
You need to list all the targets that are meant to be phony targets as prerequisites of the .PHONY target instead of just writing .PHONY: %.
.PHONY: % doesn't do what you think it does (i.e., turning every target into a phony target).
As an example, consider the following makefile:
.PHONY: %
foo:
#echo creating $#
#touch $#
For this makefile above:
$ make
creating foo
$ make
make: 'foo' is up to date.
Therefore, the target foo is not turned into a phony target by having .PHONY: % in your makefile. Otherwise, foo's recipe would have been executed, since phony targets are always outdated.

Makefile skips dependency

I've created a makefile for my little project
.SUFFIXES:
%.cpp:
$(COMP) -c -o $(subst .cpp,.o,$#) $(SRCDIR)$# $(CFLAGS)
platformL: COMP:=gcc
platformL: $(FILES)
$(COMP) -o $(NAME) $(subst .cpp,.o,$(FILES)) $(CFLAGS)
rm $(subst .cpp,.o,$(FILES))
platformW: COMP:=wine gcc
platformW: $(FILES)
$(COMP) -o $(NAME).exe $(subst .cpp,.o,$(FILES)) $(CFLAGS)
rm $(subst .cpp,.o,$(FILES))
default: platformL platformW
echo Done!
Everything worked fine until I branched to 2 different platforms, 'make' command executes only my platformL branch. After spending some time with it I discovered that adding '.PHONY' won't fix the problem. Also, it appears that only the first branch from the top gets executed (I have put the lines of platformW before platformL and only Windows compilation was performed).
How can I make it execute both branches?
Make always builds the first explicit target (and all prerequisites of the first explicit target) in the makefile, by default. That's all it will build by default.
You can either specify multiple things to build on the command line, like make platformL platformW, or you can add a new first target that depends on all the other targets you want built. By tradition that target is named all but you can call it whatever you want:
all: platformL platformW
.PHONY: all
...
platformL: ...
...
platformW: ...

Match patten rule before explicit rule

I'm trying to generically add some behaviour to every target in a Makefile, without modifying the targets.
My current attempt is thus:
%: $*
#echo 'Logging $* target'
.PHONY: test
test:
#echo 'Inside explicit test target'
When I run make test, I'd like to match the % pattern rule, which would execute test as a prerequisite ($* expanding to the pattern stem), and then log the target that was run.
$ make test
Inside explicit test target
Logging test target
Instead, what happens is that make test matches the explicit test target (presumably since it's a closer match):
$ make test
Inside explicit test target
How can I get this to work, without changing the explicit test target?
EDIT:
Another attempt...
.SECONDEXPANSION:
%: $$*
#echo 'Logging $* target'
results in
$ make test
make: Circular Makefile <- Makefile dependency dropped.
inside actual test target
I appears from your own answer, which has beaten me to the punch, that
you're concerned only to trigger a preliminary action for targets that are
mentioned on the commandline - $(MAKECMDGOALS). From the posting I took
it that you wanted such an action for "every target in a Makefile", which
would include all targets that are prerequisite to the commandline targets or,
if there are no commandline targets, to the default target.
Anyhow, you may still be interested in a solution to the more general problem.
You want a preliminary action to be executed before the recipe for every target.
Your question is: how to match a patten rule before explicit rule?
This is an XY way of posing the problem, because make will consult pattern
rules to find a way of making a target only if you don't give it an explicit
recipe. You know, for example, that make has a pre-defined pattern rule for
making an .o file from a .c file. Even so, if my makefile is:
test.o:
#echo $#
then make prints test.o, without any attempt to find test.c and compile it.
And if my make file is:
test.o: test.c
#echo $#
test.c:
#echo $#
then make prints:
test.c
test.o
needing no resort to the pattern rule. But if my makefile is:
test.o: test.c
Then make says:
make: *** No rule to make target 'test.c', needed by 'test.o'. Stop
So you can't do what you're after in the way your question supposes,
because the preliminary action you want to provoke from the pattern
rule could be provoked only if there were no other action for the target.
In that case the reasons for the failures of your two posted attempts are fairly academic,
and you may wish to scroll to The Chase.
In your first attempt, with:
%: $*
#echo 'Logging $* target'
The pattern rule - which is unemployed by make test - is equivalent to:
%:
#echo 'Logging $* target'
because $* only assumes a value in the recipe, not in the pattern rule. You
can make this pattern rule be employed by making any target for which the
makefile does not provide a recipe, e.g. make nonsuch will print Logging nonsuch target;
but that is of no use.
The second attempt, with:
.SECONDEXPANSION:
%: $$*
#echo 'Logging $* target'
does the right thing to create the rule you intend to create. But the
meaning of that rule is:
<target>: <target>
#echo 'Logging <target> target'
making every target to which this rule is applied a prerequisite of itself.
Inevitably this will result in a circular dependency error for all such targets.
As you saw, this circularity does not affect the your test target because
it has an explicit recipe and does not employ the rule. But it does provoke
the surprising error:
make: Circular Makefile <- Makefile dependency dropped.
That happens because the first target that make automatically considers is
the makefile itself. Unlike the test target, you have no recipe for
the makefile; so the pattern rule applies to it, making the makefile dependent
on itself.
The Chase
You can achieve what you want by a different approach. In a actual project
it is more than likely that in any makefile you can compute a list of
all possible targets. From this you can generate a corresponding list of
auxiliary targets, say, target => target.prelim, where the
sole purpose of target.prelim is to provoke, when it should and not
otherwise, the required preliminary action for target; and you can get make
to generate a list of order-only rules, target: | target.prelim,
for each target, such that target.prelim will not be considered in determining whether target
must be made, but will be made before target whenever target needs to be made.
Here is an illustration:
SRCS := main.c foo.c
OBJS := $(SRCS:.c=.o)
TARGETS := all prog $(OBJS)
PRELIMS := $(patsubst %,%.prelim,$(TARGETS))
define prelim_rule =
$(1): | $(1).prelim
endef
$(foreach target,$(TARGETS),$(eval $(call prelim_rule,$(target))))
.PHONY: all
all: prog
prog: $(OBJS)
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $# $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(PRELIMS) prog
%.prelim:
#echo "Logging target $(#:%.prelim=%)"
#touch $#
And a sample session:
$ make
Logging target all
Logging target main.o
cc -c -o main.o main.c
Logging target foo.o
cc -c -o foo.o foo.c
Logging target prog
cc -o prog main.o foo.o
$ make
make: Nothing to be done for 'all'.
$ make clean
rm -f main.o foo.o all.prelim prog.prelim main.o.prelim foo.o.prelim prog
$ make main.o
Logging target main.o
cc -c -o main.o main.c
$ make main.o
make: 'main.o' is up to date.
$ # A prelim can't out-date its target...
$ touch main.o.prelim
$ make main.o
make: 'main.o' is up to date.
I realise that this isn't answering my question as asked, but it has the effect I want - executing a shell command as late in the Makefile processing as possible.
MYVAR?=foo
.PHONY: test
test:
#echo 'Inside test target'
LOG=$(shell echo 'Logging $(MAKECMDGOALS), myvar=$(MYVAR)' > log)
.SECONDEXPANSION:
force: $$(LOG)
LOG is a deferred variable, so is not expanded until Make evaluates the prerequisite list of the force target.
In a single Makefile, the .SECONDEXPANSION: part is not needed, since the force target is evaluated after MYVAR is set.
However, if I move the LOG variable and force variable into a sub-makefile, it would be easy to include subMakefile before the MYVAR?= line - which would not work.
By specifying .SECONDEXPANSION for force, the reliance on ordering is removed.

How do I make a makefile rule execute its prerequisites?

I have a makefile containing rules to build the system, tests, and run them. The last item is executed by just calling a shell script. Among other things, this prevents me from running the tests in parallel.
I have the following variables:
TEST_SRC=$(wildcard tests/*.c)
TESTS=$(patsubst %.c,%,${TEST_SRC})
and it builds the tests with the rule
$(TESTS): %: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $<
Is it possible (and if so, how?) to create a rule "tests" that, when run, will execute each item in the $TESTS variable?
You could do it this way:
# a separate target to run each test
RUN_TESTS = $(addprefix run_, $(TESTS))
# a pattern rule for those targets, which will remake the test iff neccessary
.PHONY: $(RUN_TESTS)
$(RUN_TESTS):run_%:%
./$<
# One Rule to Ring Them All, One Rule to... sorry.
.PHONY: tests
tests: $(RUN_TESTS)
I believe that a rule like this:
run_tests: $(TESTS)
Should do the trick:
$ make run_tests
It will not execute anything, but it will have $(TESTS) as a dependency and run them first.

Resources