Gnu make: How to create a directory in a makefile when mkdir -p is unavailable?

I have a makefile that creates a normal directory creation:

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

Unfortunately, when I run this under scratchbox2, the mkdir -p command always fails.

I tried to execute the following kludge, which does not work:

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

It is output:

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 /

... the trailing slash prevents the dir function from deleting the last directory the way I wanted.

Finishing up with a script or small C application to replicate the "-p" function, does anyone have any ideas for creating subdirectories in the makefile?

Without the -p option, mkdir will throw an error when the makefile tries to create a directory that already exists. I can do mkdir blah 2> / dev / null, but then I risk losing other error messages.

Does anyone have any thoughts on why mkdir -p does not work under scratchbox2?

EDIT

Based on bobbogo's suggestions, I put this together. It looks pretty confusing, but it seems to work even under scratchbox2.

 # 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 $@ 
+8
mkdir gnu-make scratchbox
source share
3 answers

You can replace the mkdir forest as follows:

 $(Release_target_OBJDIR)/%.o: %.cpp $(foreach d,$(subst /, ,${@D}),mkdir $d && cd $d && ): ∶ 

This will create a shell command something like this:

 mkdir projects && cd projects && mkdir htc && cd htc && mkdir arm && cd arm && : 

This is done for each compiler. Not very elegant. You can optimize this using some kind of sentinel file. For example:

 $(Release_target_OBJDIR)/%.o: %.cpp ${Release_target_OBJDIR}/.sentinel ∶ %/.sentinel: $(foreach d,$(subst /, ,$*),mkdir $d && cd $d && ): touch $@ 

.sentinel is created once in front of all objects and make -j friendly. In fact, you should do it this way, even if mkdir -p works for you (in this case you would use mkdir -p rather than the $(foreach) hack solution).

+4
source share

You can tell make ignore any failure return code from the command with - :

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

(Note that this does not apply to the end slash issue.)

0
source share

There is an easier way. You can call mkdir inside the shell function as follows:

 foobar:
         $ (shell mkdir -p mydirectoryname)

The shell function in gnu make executes commands after the word shell as a shell command.

0
source share

All Articles