Подавить вывод ошибки правила make

У меня есть правило, которое создает каталог

bin:
    -mkdir $@

Однако после первого создания каталога я получаю следующий вывод:

mkdir bin
mkdir: cannot create directory `bin': File exists
make: [bin] Error 1 (ignored)

Есть ли способ запустить правило только в том случае, если каталог не существует, или подавить вывод, если каталог уже существует?


person Matt Joiner    schedule 13.08.2010    source источник
comment
Почти дубликат: stackoverflow.com/questions/3477292/   -  person reinierpost    schedule 24.08.2010


Ответы (6)


Традиционный способ создания каталога - использовать файл штампа, от которого зависит и создает каталог в качестве побочного эффекта. Удалите файл штампа при создании distclean или любой другой "действительно чистой" цели:

bin/.dirstamp:
    mkdir -p $(DIRS)
    touch $@

bin/foo: bin/.dirstamp
    $(MKFOO) -o $@

distclean:
    rm -rf bin

Причина этого заключается в следующем: всякий раз, когда файл в bin создается / удаляется, время mtime содержащего его каталога обновляется. Если цель зависит от bin, то при следующем запуске make она заново создаст файлы, которые ей не нужны.

person Jack Kelly    schedule 24.08.2010
comment
Переходит ли директория ко всем файлам, сгенерированным в этом месте? - person Matt Joiner; 24.08.2010
comment
Каждый файл, созданный в этом каталоге, должен прямо или косвенно зависеть от файла штампа, чтобы гарантировать его создание перед использованием. - person Jack Kelly; 24.08.2010

Другой способ подавить вывод make: error ... (ignored) - добавить || true к команде, которая может завершиться ошибкой. Пример с grep, который проверяет наличие ошибок в файле журнала LaTeX:

undefined:
  @grep -i undefined *.log || true

Без || true команда make выдает жалобы, когда grep не может найти совпадений.

Это работает для всех команд, а не только для mkdir; вот почему я добавил этот ответ.

person daniel kullmann    schedule 16.04.2012
comment
daniel, символ префикса - для команды в правиле make делает то же самое, хотя и не требует, чтобы оболочка обрабатывала его. Это, вероятно, быстрее и с меньшей вероятностью приведет к обратным результатам. - person Matt Joiner; 16.04.2012
comment
Префикс - заставляет make выводить досадную ошибку с игнорированием вывода, чего нет в моем решении. Так что нет, они не делают одно и то же. - person daniel kullmann; 17.04.2012
comment
Это работает только как ||: (труба-труба-двоеточие) в моей сборке Windows. - person Engineer; 22.07.2015

Ошибка игнорируется уже начальным символом «-» в командной строке. Если вы действительно хотите потерять сообщения об ошибках от mkdir, используйте перенаправление ввода-вывода:

bin:
    -mkdir bin 2> /dev/null

Однако вы по-прежнему будете получать предупреждение об игнорировании от make, поэтому, возможно, лучше использовать параметр mkdir, который не приводит к сбою, когда цель уже существует, а именно параметр -p:

MKDIR_P = mkdir -p

bin:
    ${MKDIR_P} $@

Параметр -p фактически создает все каталоги, которые отсутствуют на заданных путях, поэтому он может сгенерировать несколько каталогов за один вызов, но побочным эффектом является то, что он не генерирует ошибку для уже существующих каталогов. Это предполагает реализацию mkdir в стиле POSIX; старые машины могут не поддерживать его (хотя уже давно это стандарт).

person Jonathan Leffler    schedule 13.08.2010
comment
почему такое 2>&1 перенаправление помогает? Я бы понял 2>/dev/null отправить stderr в забвение, но отправив его на stdout .....? - person humanityANDpeace; 09.03.2016
comment
@humanityANDpeace: Вы правы - думаю, еще в 2010 году. Я исправил это. Спасибо. - person Jonathan Leffler; 09.03.2016

Что ж, у меня получилась эта конструкция, может быть, кому-то она пригодится или прокомментирует:

BINDIR = .
TMPDIR = tmp
OUTDIRS = $(BINDIR) $(TMPDIR)
$(OUTDIRS):
    @test -d $@ || mkdir $@
person Matt Joiner    schedule 14.08.2010
comment
Make в любом случае делает test за вас, так что в итоге он статирует каталог дважды. Это просто скрывает проблему, заключающуюся в том, что целью по умолчанию является. (Точка). - person Maxim Egorushkin; 20.08.2010

Правило не должно выполняться, если его цель не существует или устарела из-за зависимостей. Другими словами, вы никогда не должны столкнуться с этой ошибкой.

[Пример добавлен]

[max@truth tmp]$ ls -la
total 20
drwxr-xr-x.  2 max users 4096 Aug 14 21:11 .
drwx------. 80 max max   4096 Aug 14 18:25 ..
-rw-rw-r--   1 max max     38 Aug 14 21:11 Makefile
[max@truth tmp]$ cat Makefile 
.PHONY: all
all: bin

bin:
    mkdir $@

[max@truth tmp]$ make
mkdir bin
[max@truth tmp]$ ls -la
total 24
drwxr-xr-x.  3 max users 4096 Aug 14 21:11 .
drwx------. 80 max max   4096 Aug 14 18:25 ..
drwxrwxr-x   2 max max   4096 Aug 14 21:11 bin
-rw-rw-r--   1 max max     38 Aug 14 21:11 Makefile
[max@truth tmp]$ make
make: Nothing to be done for `all'.
[max@truth tmp]$ make
make: Nothing to be done for `all'.

Ваша папка от чего-нибудь зависит? Ваша папка - фальшивая цель?

person Maxim Egorushkin    schedule 13.08.2010
comment
Неа. Это всегда устарело, то, что вы видите в OP, - это то, что есть у меня. - person Matt Joiner; 14.08.2010

Make предполагает, что первая цель является целью по умолчанию. Если это ваш полный make-файл, то он всегда должен пытаться переделать цель по умолчанию, которой является bin. Вставьте следующие строки в верхнюю часть вашего make-файла:

all: bin
.PHONY: all
person Maxim Egorushkin    schedule 20.08.2010