Управление многословием

Я использую make файл для компиляции программы из многих файлов .c, и в любое время make вызывается только компилирует те файлы, которые были изменены после последнего запуска (ничего особенного до сих пор).

Чтобы избежать загромождения моего экрана, я добавляю @ в начале каждого вызова $(CC), и перед этим я печатаю настроенное сообщение echo. Например:

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

Мой вопрос: как я могу управлять многословием make более "динамическим способом", чтобы иметь возможность:

  • Нормальное поведение: для каждого выполненного правила файла напечатано только настроенное сообщение.
  • Подробное поведение: напечатайте команду, фактически выполняемую каждым правилом makefile (как будто @ вообще не использовался).

Ответ 1

Я бы сделал так, как делает automake:

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)[email protected]$(MATHOPTS)

Если вам нужно выполнить другие команды в своих правилах, мне нравится следующий фрагмент. Запишите $(AT) вместо @ и он будет молчать, когда V=0, но будет напечатан, когда V=1.

AT_0 := @
AT_1 := 
AT = $(AT_$(V))

Ответ 2

Другое решение (которое мне нравится, потому что оно гибкое)

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

%.o: %.c
    $(vecho) "-> Compiling [email protected]"
    $(Q)$(CC) $(CFLAGS) -c $< -o [email protected]

Вы можете пропустить материал vecho, но иногда это пригодится.

Ответ 3

Я бы создал функцию, которая принимает команду для выполнения и решает, следует ли ее эхо.

# '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)[email protected]$(MATHOPTS), \
        Compiling $<)

Тогда результатом простого вызова make будет что-то вроде:

Compiling foo.c

В то время как make V=1 даст:

gcc -Wall -c foo.c -o foo.o ...

Ответ 4

Вместо того, чтобы компилировать "@gcc", вы можете опустить это "@" и передать вместо этого команду "-s" в свою команду make. (Оставьте "@echo" так, как есть.) Тогда "make -s" будет вашей короткой командой make, а "make" будет многословной.

Флаг '-s или' --silent для предотвращения всех эхо-сигналов, как будто все рецепты начинаются с '@.

На страницах GNU Make manual

(Другой ответ лучше отвечает на ваш вопрос, но этот подход заслуживает упоминания.)

Ответ 5

Так как я не могу прокомментировать предложение AT = $(AT_$(V)), обратите внимание, что Automake предоставляет стандартный макрос, который выполняет те же действия, что и AT, который называется AM_V_at.

Вы также обнаружите, что у него есть другая очень полезная переменная AM_V_GEN, которая разрешает либо ничего, либо @echo " GEN " [email protected];, в зависимости от многословия.

Это позволяет вам закодировать что-то вроде этого:

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

Выход из него будет либо (с расширением verbosity):

  GEN    grldr.mbr

или (многословие включено):

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

Довольно удобно, и это устраняет необходимость определять собственные макросы.