как предотвратить ошибку «каталог уже существует» в make-файле при использовании mkdir
Вопрос
Мне нужно создать каталог в моем make-файле, и я бы не хотел снова и снова получать сообщение об ошибке «каталог уже существует», даже если я могу легко его проигнорировать.
В основном я использую mingw/msys, но хотелось бы, чтобы что-то работало и в других оболочках/системах.
Я попробовал это, но это не сработало, есть идеи?
ifeq (,$(findstring $(OBJDIR),$(wildcard $(OBJDIR) )))
-mkdir $(OBJDIR)
endif
Решение
В UNIX Просто используйте это:
mkdir -p $(OBJDIR)
Опция -p команды mkdir предотвращает появление сообщения об ошибке, если каталог существует.
Другие советы
Смотря на официальная документация производителя, вот хороший способ сделать это:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir -p $(OBJDIR)
Вы должны увидеть здесь использование | Оператор трубы, определяющий только заказ только обязанности.Это означает, что $(OBJDIR)
цель должна существовать (вместо более свежий), чтобы построить текущую цель.
Обратите внимание, что я использовал mkdir -p
.А -p
флаг был добавлен по сравнению с примером из документации.Смотрите другие ответы для другой альтернативы.
Вы можете использовать тестовую команду:
test -d $(OBJDIR) || mkdir $(OBJDIR)
Вот трюк, который я использую с GNU make для создания каталогов вывода компилятора.Сначала определите это правило:
%/.d:
mkdir -p $(@D)
touch $@
Затем сделайте все файлы, попадающие в каталог, зависимыми от файла .d в этом каталоге:
obj/%.o: %.c obj/.d
$(CC) $(CFLAGS) -c -o $@ $<
Обратите внимание на использование $< вместо $^.
Наконец, запретите автоматическое удаление файлов .d:
.PRECIOUS: %/.d
Пропустить файл .d и напрямую зависеть от каталога не получится, поскольку время изменения каталога обновляется каждый раз, когда в этом каталоге записывается файл, что приведет к принудительному перестроению при каждом вызове make.
Если наличие уже существующего каталога для вас не проблема, вы можете просто перенаправить stderr для этой команды, избавившись от сообщения об ошибке:
-mkdir $(OBJDIR) 2>/dev/null
Внутри вашего make-файла:
target:
if test -d dir; then echo "hello world!"; else mkdir dir; fi
В Windows
if not exist "$(OBJDIR)" mkdir $(OBJDIR)
На Unix | Linux
if [ ! -d "$(OBJDIR)" ]; then mkdir $(OBJDIR); fi
ifeq "$(wildcard $(MY_DIRNAME) )" ""
-mkdir $(MY_DIRNAME)
endif
$(OBJDIR):
mkdir $@
Это также работает для нескольких каталогов, например.
OBJDIRS := $(sort $(dir $(OBJECTS)))
$(OBJDIRS):
mkdir $@
Добавление $(OBJDIR)
поскольку первая цель работает хорошо.
Он работает под mingw32/msys/cygwin/linux.
ifeq "$(wildcard .dep)" ""
-include $(shell mkdir .dep) $(wildcard .dep/*)
endif
Если вы явно игнорируете код возврата и выгружаете поток ошибок, то ваш make будет игнорировать ошибку, если она произойдет:
mkdir 2>/dev/null || true
Это не должно вызвать опасность гонки в параллельной версии, но я не проверял это, чтобы быть уверенным.
Немного проще, чем ответ Ларса:
something_needs_directory_xxx : xxx/..
и общее правило:
%/.. : ;@mkdir -p $(@D)
Никаких сенсорных файлов, которые нужно очищать или делать .PRECIOUS :-)
Если вы хотите увидеть еще один небольшой общий трюк с gmake или если вас интересует нерекурсивный make с минимальными каркасами, вы можете проверить Еще два дешевых трюка с Gmake и другие сообщения, связанные с make, в этом блоге.