14

I'm using a makefile to compile a program made of many .c files, and any time make is invoked it only compiles those files modified after the last run (nothing special until here).

To avoid cluttering my screen, I prepend @ at the beginning of each $(CC) call, and before it I print a customized echo message. For example:

%.o: %.c $(h1) $(h3) %.h
    @echo -e "\tCompiling <" $< 
    @$(CC) $(CFLAGS) -c $< -o $(libDir)$@$(MATHOPTS)

My question is: how can I control the verbosity of make in a more "dynamic way", in order to be able to:

  1. Normal behaviour: only a customized message is printed for every makefile rule executed.
  2. Verbose behaviour: print the command actually executed by every makefile rule (as if the @ wasn't used at all).
Nicolás Ozimica
  • 9,481
  • 5
  • 38
  • 51

5 Answers5

18

I'd do it the way automake does:

V = 0
ACTUAL_CC := $(CC)
CC_0 = @echo "Compiling $<..."; $(ACTUAL_CC)
CC_1 = $(ACTUAL_CC)
CC = $(CC_$(V))

%.o: %.c $(h1) $(h3) %.h
        $(CC) $(CFLAGS) -c $< -o $(libDir)$@$(MATHOPTS)

If you need to execute other commands in your rules, I like the following snippet. Write $(AT) instead of @ and it will be silent when V=0 but printed when V=1.

AT_0 := @
AT_1 := 
AT = $(AT_$(V))
xaizek
  • 5,098
  • 1
  • 34
  • 60
Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
  • 2
    In your first part I suppose one also need to override `CC = $(CC_$(V))`. – dma_k Feb 16 '12 at 22:20
  • 1
    Yes. It's absence was a brain fart that I'll fix now. I should also point out that recursive variable expansion is widely implemented but not currently in POSIX (but that will change in a future revision). – Jack Kelly Feb 17 '12 at 07:34
  • 1
    Great solution @JackKelly. The one creating the `AT` variable is simple and effective!. – Nicolás Ozimica Feb 22 '12 at 18:47
  • Your code does not work for me. I get https://gist.github.com/JasonGross/7103651. – Jason Gross Oct 22 '13 at 16:23
  • 1
    I had to do `CC := $(CC_$(V))` (note the colon) to stop `make` from complaining that 'Recursive variable CC references itself'. Did I do something wrong? – larsr Mar 04 '14 at 10:51
  • This is not working for me either. I get "Makefile:12: *** Recursive variable 'CC' references itself (eventually). Stop." When using exactly the first solution. Im using "GNU Make 4.0" – netdigger Dec 06 '15 at 11:05
  • @everlof, edited to fix that error, seems to work fine now. – xaizek Jan 11 '16 at 17:14
  • Why not just use the `.SILENT:` special target? It's fully generic (don't need to redefine all the the program variables like `CC`, `CXX`, `LD`, `AR`, etc.). A more complete discussion with examples is available at: http://make.mad-scientist.net/managing-recipe-echoing/ The `.SILENT` target is part of POSIX so it should work everywhere, very easily. The only difference from this is it prints the output of the `echo` (but not the `echo` command itself) even in verbose mode. – MadScientist Jul 02 '17 at 18:34
10

Another solution (one which I like because it's flexible)

ifeq ("$(BUILD_VERBOSE)","1")
Q :=
vecho = @echo
else
Q := @
vecho = @true
endif

%.o: %.c
    $(vecho) "-> Compiling $@"
    $(Q)$(CC) $(CFLAGS) -c $< -o $@

You can skip the vecho stuff, but it does come in handy at times.

John
  • 3,400
  • 3
  • 31
  • 47
6

Instead of using "@gcc" to compile, you can omit that "@" and pass the "-s" option to your make command instead. (Leave "@echo" as it is.) Then "make -s" would be your brief make command, and "make" would be verbose.

The ‘-s’ or ‘--silent’ flag to make prevents all echoing, as if all recipes started with ‘@’.

From the GNU Make manual pages

(The other answers better answer your question, but this approach deserves a mention.)

John P
  • 1,463
  • 3
  • 19
  • 39
4

I would create a function which takes a command to execute and decides whether to echo it.

# 'cmd' takes two arguments:
#   1. The actual command to execute.
#   2. Optional message to print instead of echoing the command
#      if executing without 'V' flag.
ifdef V
cmd = $1
else
cmd = @$(if $(value 2),echo -e "$2";)$1
endif

%.o: %.c $(h1) $(h3) %.h
    $(call cmd, \
        $(CC) $(CFLAGS) -c $< -o $(libDir)$@$(MATHOPTS), \
        Compiling $<)

Then the result of plain make invocation will be something like:

Compiling foo.c

Whereas make V=1 will give:

gcc -Wall -c foo.c -o foo.o ...
Eldar Abusalimov
  • 24,387
  • 4
  • 67
  • 71
  • Thanks @Eldar! Your suggestion is very good, but redefining the "@" as proposed by Jack is simpler. BTW, I didn't know at all that you could define a function that way. – Nicolás Ozimica Feb 22 '12 at 18:49
3

Since I can't comment on the AT = $(AT_$(V)) suggestion, note that Automake does provide a standard macro that does the same thing as AT, which is called AM_V_at.

You will also find that it has another very useful AM_V_GEN variable, that resolves either to nothing or to @echo " GEN " $@;, depending on the verbosity.

This allows you to code something like this:

grldr.mbr: mbrstart
    $(AM_V_GEN)
    $(AM_V_at)-rm -f grldr.mbr
    $(AM_V_at)cat mbrstart > grldr.mbr

The output of which will be either (verbosity disabled):

  GEN    grldr.mbr

or (verbosity enabled):

rm -f grldr.mbr
cat mbrstart > grldr.mbr

Pretty convenient, and this removes the need to define your own macros.

Akeo
  • 271
  • 3
  • 17