Today’s compiler invocations often utilize a large number of flags and options, which can make reading the output from a make
invocation difficult. But what’s the best way to provide cleaner build output while still maintaining the ability to see the entire recipe, when necessary?
I’ve seen this handled various ways, but the simplest and most effective, in my opinion, is to utilize the .SILENT
special target.
For this method we prefix the recipe lines which we never want to be echoed, even during a verbose build, with the standard @
character. Typically this would include lines which invoke echo
or printf
which show output, and we don’t need to see the command that generates the output.
All other recipe lines we leave alone, and do not prefix then with anything. Instead, we add the .SILENT
special target to our makefile. This causes all recipe lines to be treated as if they were prefixed with @
, so our makefile by default is “quiet” and doesn’t display the full recipe command lines.
Next we want to have a simple way of disabling the .SILENT
target, without having to edit our makefile and comment it out. An easy way to do that is prefix it with some variable, which is normally empty. Say we choose the variable V
, for “verbose”. Now if we set that variable to some non-empty value, for example on the make command line or even in the environment, the .SILENT
target will be disabled.
Here’s an example makefile using this method:
all: myprog .PHONY: all myprog: myprog.o mymisc.o myfunc.o @echo "LINK $@" $(CC) -o $@ $(LDFLAGS) $^ $(LDLIBS) %.o : %.c @echo "CC $<" $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $< $(V).SILENT:
When invocating make
with this makefile, the .SILENT
special target will be in effect and none of the recipe lines will be printed. The output would be something like:
$ make CC myprog.c CC mymisc.c CC myfunc.c LINK myprog
However if you wanted a verbose build you would set V=1
(or any other value, really) on the make
command line. Now instead of the .SILENT
target this makefile defines the 1.SILENT
target, which doesn’t mean anything special to make
. Thus, any command line not prefixed with @
will be printed, giving you output like this:
$ make V=1
CC myprog.c
gcc -c -o myprog.o myprog.c
CC mymisc.c
gcc -c -o mymisc.o mymisc.c
CC myfunc.c
gcc -c -o myfunc.o myfunc.c
LINK myprog
gcc -o myprog myprog.o mymisc.o myfunc.o
What makes this method nice is that first, in addition to your output being cleaner your makefile recipes are cleaner: no need to prefix all recipe lines with special variables for example. And second, your recipe lines are not output in “quiet mode” and shown in “verbose mode” by default; you don’t have to remember to do anything different to them.