Sometimes when you are running a make you'd like to see what commands get executed (even if they've been muted by prefixing them with
@) and where in the makefile those commands reside. But you can't. There's no way to override
@ and
make -n doesn't actually run the make.
But here's 'one weird trick' that makes it possible to see inside a make as its running. Just add this to the makefile:
_SHELL := $(SHELL) SHELL = $(warning [$@])$(_SHELL) -x Before digging into how that gives you makefile X-ray vision, let's take a look at it in action. Here's an example makefile that builds an executable from
foo.o and
bar.o (which are built from corresponding
foo.c and
bar.c files).
.PHONY: all all: runme
runme: foo.o bar.o ; @$(LINK.o) $^ -o $@ foo.o: foo.c bar.o: bar.c
%.o: %.c ; @$(COMPILE.C) -o $@ $< Running simply
make on this performs the compiles and link but produces no output because output has been suppressed by the
@ signs on the compile and link commands. Running a
make -n gives this output:
% make -n g++ -c -o foo.o foo.c g++ -c -o bar.o bar.c cc foo.o bar.o -o runme That's handy, but doesn't tell the whole story. For example, which of those lines correspond to which targets? And where are the actual commands found in the makefile?
But add the two lines above to the makefile and do a normal
make and everything becomes clear:
% make Makefile:9: [foo.o] + g++ -c -o foo.o foo.c Makefile:9: [bar.o] + g++ -c -o bar.o bar.c Makefile:4: [runme] + cc foo.o bar.o -o runme It's easy to see that
foo.o is built by the rule on line 9 of a makefile called
Makefile (the
%.o: %.c pattern rule) and that the link is on line 4. As each rule runs the location of the rule (with the corresponding target) is output followed by the actual commands.
How that works
The first line of the trick defines a variable called
_SHELL and captures the value of the built-in
SHELL variable using
:=.
SHELL contains the path (and parameters) for the shell that will be used to execute commands.
Then
SHELL itself is redefined (this time using
= and not
:=) to contains a
$(warning) and the original shell command (from
_SHELL) with
-x added. The
-x causes the shell to print out commands being executed.
Since
SHELL gets expanded for every recipe in the makefile, as it runs the
$(warning) gets expanded and outputs the specific makefile line where the recipe can be found and
$@ will be valid and contain the name of the target being built.
Caveat: doing this will slow down a build as GNU make doesn't use the shell if it can avoid it. If
SHELL is untouched in a makefile the GNU make short-circuits the shell and execs commands directly if it can.
More?
If that sort of thing interests you, you might enjoy my book:
The GNU Make Book.