Как создать каталог в make-файле, когда mkdir -p недоступен?
У меня есть make-файл, который делает обычное создание каталога:
$(Release_target_OBJDIR)/%.o: %.cpp
mkdir -p $(dir $@)
$(COMPILE.cpp) $< $(CFLAGS) $(INCLUDES) -o $@
К сожалению, когда я запускаю это в scratchbox2, команда mkdir -p всегда завершается неудачно.
Я попытался следующий kludge, который не работает:
$(Release_target_OBJDIR)/%.o: %.cpp
mkdir $(dir $(dir $(dir $@)))
mkdir $(dir $(dir $@))
mkdir $(dir $@)
$(COMPILE.cpp) $< $(CFLAGS) $(INCLUDES) -o $@
Это выводит:
mkdir -p /home/foo/projects/htc/arm/obj/cbar/release/
mkdir -p /home/foo/projects/htc/arm/obj/cbar/release/
mkdir -p /home/foo/projects/htc/arm/obj/cbar/release/
... завершающий слеш не позволяет функции dir удалять последний каталог так, как я хотел.
Если не считать сценария или небольшого приложения на C для репликации функциональности "-p", есть ли у кого-нибудь идеи по созданию подкаталогов в make-файле?
Без опции -p mkdir выдаст ошибку, когда make-файл попытается создать каталог, который уже существует. Я могу сделать mkdir blah 2> /dev/null, но тогда я рискую потерять другие сообщения об ошибках.
У кого-нибудь есть мысли о том, почему mkdir -p не работает под scratchbox2?
РЕДАКТИРОВАТЬ
Основываясь на предложениях bobbogo, я собрал это. Это выглядит довольно запутанным, но, кажется, работает, даже под нуля2.
# Generic variables for use in functions
comma:= ,
empty:=
space:= $(empty) $(empty)
# Make directory function
forlooprange = $(wordlist 1,$(words $1),1 2 3 4 5 6 7 8 9 10)
forloop = $(foreach n,$(call forlooprange,$1),$(call $2,$n,$3))
mkdirfunc0 = test -d $1 || mkdir $1;
mkdirfunc1 = $(call mkdirfunc0,/$(subst $(space),/,$(foreach n,$(wordlist 1,$1,$2),$n)))
mkdirfunc2 = $(call forloop,$1,mkdirfunc1,$1)
mkdirmain = $(call mkdirfunc2,$(subst /, ,$1))
.PRECIOUS: %/.sentinel
%/.sentinel:
$(call mkdirmain,$*)
touch $@
3 ответа
Вы можете заменить свой лес mkdir
с этим:
$(Release_target_OBJDIR)/%.o: %.cpp
$(foreach d,$(subst /, ,${@D}),mkdir $d && cd $d && ):
∶
Это создаст команду оболочки примерно так:
mkdir projects && cd projects && mkdir htc && cd htc && mkdir arm && cd arm && :
Это работает для каждой компиляции. Не очень элегантно Вы можете оптимизировать это, используя какой-нибудь сторожевой файл. Например:
$(Release_target_OBJDIR)/%.o: %.cpp ${Release_target_OBJDIR}/.sentinel
∶
%/.sentinel:
$(foreach d,$(subst /, ,$*),mkdir $d && cd $d && ):
touch $@
.sentinel
создается один раз перед всеми объектами, и make -j
дружелюбный. На самом деле вы должны сделать это таким образом, даже если mkdir -p
работает для вас (в этом случае вы бы использовать mkdir -p
а не $(foreach)
взломать решение).
Ты можешь сказать make
игнорировать любой код возврата ошибки из команды, использующей -
:
$(Release_target_OBJDIR)/%.o: %.cpp
-mkdir $(dir $(dir $(dir $@)))
-mkdir $(dir $(dir $@))
-mkdir $(dir $@)
$(COMPILE.cpp) $< $(CFLAGS) $(INCLUDES) -o $@
(Обратите внимание, что это не решает проблему с косой чертой.)
Есть более простой способ. Вы можете вызвать mkdir внутри функции оболочки следующим образом:
Foobar: $(shell mkdir -p mydirectoryname)
shell
функция в GNU Make выполняет команды после слова shell
в качестве команды оболочки.