I have a makefile which does the usual 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 silently.
I attempted the following kludge which doesn't work:
$(Release_target_OBJDIR)/%.o: %.cpp
mkdir $(dir $(dir $(dir $@)))
mkdir $(dir $(dir $@))
mkdir $(dir $@)
$(COMPILE.cpp) $< $(CFLAGS) $(INCLUDES) -o $@
This outputs:
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 stripping the last directory in the way I wanted.
Short of writing a script or small C app to replicate the "-p" functionality, does anyone have any ideas for creating the subdirectories within the makefile?
Without the -p option mkdir will give an error when the makefile tries to create a directory which already exists. I can do mkdir blah 2> /dev/null but then I risk losing other error messages.
Does anyone have any thoughts as to why mkdir -p doesn't work under scratchbox2?
EDIT
Based on suggestions by bobbogo I put this together. It looks fairly convoluted, but 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 $@
To use this makefile, simply cd to the directory and type “ makepp ”. Makepp will attempt to build the first target in the makefile, which is my_program . (If you don't want it to build the first target, then you have to supply a the name of the target you actually want to build on the command line.)
You can use shell function: current_dir = $(shell pwd) . Or shell in combination with notdir , if you need not absolute path: current_dir = $(notdir $(shell pwd)) .
Yes, a Makefile can have a directory as target. However, you shouldn't. When a file is added or removed from a directory, its mtime is updated. This can cause weird behaviour by causing multiple targets depending on a single directory to become implicitly rebuilt by one another.
You can use the Java File class to create directories if they don't already exists. The File class contains the method mkdir() and mkdirs() for that purpose. The mkdir() method creates a single directory if it does not already exist.
You can replace your forest of mkdir
s with this:
$(Release_target_OBJDIR)/%.o: %.cpp
$(foreach d,$(subst /, ,${@D}),mkdir $d && cd $d && ):
∶
This will create a shell command somethng like this:
mkdir projects && cd projects && mkdir htc && cd htc && mkdir arm && cd arm && :
This runs for every compile. Not very elegant. You could optimise this by using some sort of sentinel file. For instance:
$(Release_target_OBJDIR)/%.o: %.cpp ${Release_target_OBJDIR}/.sentinel
∶
%/.sentinel:
$(foreach d,$(subst /, ,$*),mkdir $d && cd $d && ):
touch $@
.sentinel
gets created once before all objects, and is make -j
friendly. In fact you should do it this way even if mkdir -p
works for you (in which case you would use mkdir -p
rather than the $(foreach)
hacksolution).
You can tell make
to ignore any failure return code from a command using -
:
$(Release_target_OBJDIR)/%.o: %.cpp
-mkdir $(dir $(dir $(dir $@)))
-mkdir $(dir $(dir $@))
-mkdir $(dir $@)
$(COMPILE.cpp) $< $(CFLAGS) $(INCLUDES) -o $@
(Note that this doesn't address the trailing slash problem.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With