У меня есть правило, которое создает каталог
bin:
-mkdir $@
Однако после в первый раз, когда каталог был сгенерирован, я получаю этот вывод:
mkdir bin
mkdir: cannot create directory `bin': File exists
make: [bin] Error 1 (ignored)
Есть ли некоторый способ, которым я могу только выполнить правило, если каталог не существует или подавляет вывод, когда каталог уже существует?
Традиционным способом создания каталога является использование файла штампа, от которого зависит создание каталога в качестве побочного эффекта. Удалите файл штампа при выполнении distclean
или любой другой вашей «действительно чистой» цели:
bin/.dirstamp:
mkdir -p $(DIRS)
touch $@
bin/foo: bin/.dirstamp
$(MKFOO) -o $@
distclean:
rm -rf bin
Причина этого следующая: всякий раз, когда файл в bin
создается/удаляется, обновляется mtime содержащего каталога. Если цель зависит от bin
, то при следующем запуске make
она воссоздаст файлы, которые ей не нужны.
Ошибка игнорируется уже ведущими '-
' в командной строке. Если вы действительно хотите потерять сообщения об ошибках от mkdir
, используйте перенаправление ввода/вывода:
bin:
-mkdir bin 2> /dev/null
Однако вы все равно получите предупреждение 'ignored' от make
, поэтому лучше использовать опцию к mkdir
, которая не вызывает ошибку, когда цель уже существует, а именно опцию -p
:
MKDIR_P = mkdir -p
bin:
${MKDIR_P} $@
Опция -p
фактически создает все каталоги, которые отсутствуют в заданных путях, поэтому она может создать большое количество каталогов за один вызов, но побочным эффектом является то, что она не выдает ошибку для уже существующих каталогов. Это предполагает POSIX-подобную реализацию mkdir
; старые машины могут ее не поддерживать (хотя она уже давно является стандартной).
Правило не должно выполняться, если его цель не существует или устарела из-за своих зависимостей. Другими словами, вы никогда не должны столкнуться с этой ошибкой.
[Пример добавлен]
[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'.
Ваша папка от чего-либо зависит? Ваша папка - фальшивая цель?
Я закончил с этой конструкцией, может быть, кто-то сочтет ее полезной или прокомментирует ее:
BINDIR = .
TMPDIR = tmp
OUTDIRS = $(BINDIR) $(TMPDIR)
$(OUTDIRS):
@test -d $@ || mkdir $@
Make предполагает, что первая цель является целью по умолчанию. Если это ваш полный make-файл, то он всегда должен пытаться переделать цель по умолчанию, которой является bin. Вставьте следующие строки в начало вашего make-файла:
all: bin
.PHONY: all