Как создать каталог в make-файле, когда mkdir -p недоступен? - PullRequest
8 голосов
/ 04 марта 2011

У меня есть 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?

EDIT

На основании предложений Боббого Я собрал это. Это выглядит довольно запутанным, но, кажется, работает, даже под нуля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 ]

4 голосов
/ 04 марта 2011

Вы можете заменить свой лес mkdir s следующим:

$(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) hack решение).

2 голосов
/ 04 марта 2011

Вы можете указать make игнорировать любой код возврата ошибки из команды, используя -:

$(Release_target_OBJDIR)/%.o: %.cpp
    -mkdir $(dir $(dir $(dir $@)))
    -mkdir $(dir $(dir $@))
    -mkdir $(dir $@)
    $(COMPILE.cpp) $< $(CFLAGS) $(INCLUDES) -o $@

(Обратите внимание, что это не решает проблему с косой чертой.)

0 голосов
/ 07 декабря 2016

Есть более простой способ.Вы можете вызвать mkdir внутри функции оболочки следующим образом:

foobar:
        $(shell mkdir -p mydirectoryname)

Функция shell в gnu make выполняет команды после слова shell в качестве команды оболочки.

...