Managing Recipe Echoing

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) $<


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.