[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: how to make dirs without races
From: |
Mark Galeck |
Subject: |
Re: how to make dirs without races |
Date: |
Mon, 4 Mar 2013 19:35:37 -0800 (PST) |
Well, implicit chain does not work because of what Paul says in the manual:
"No single implicit rule can appear more than once in a chain. This means
that make will not even consider such a ridiculous thing as
making foo from foo.o.o by running the linker twice. This constraint has the
added benefit of preventing any infinite loop in the search for an implicit
rule
chain"
I think I disagree with this. I would want a convenient implicit rule that
would make a directory (recognized by trailing /.) depend on the parent,
knowing
that the chain will eventually have to end with an existing directory.
I need to depend on the parent, because if I don't, mkdir -p has a side effect,
which violates Paul's rules of makefiles, and for a good reason - that creates
a
race condition.
In the absence of that, I have to go explicit. It is probably faster, OK, but
I
better hide this from the developers, for they will scream in horror. The user
calls the function
$(call MAKE_DIR,<directory>)
If anybody knows how to do this (make any directory, without race conditions,
possibly with irregular strings such as foo/../bar, and without any make
warnings about duplicate rules) easier than the below, please show me.
########################################
# make dir $(1) without race conditions
#
# you can just
# $(call MAKE_DIR,<directory>)
#
# for convenience, this is redirected to MAKE_DIR_F
########################################
MAKE_DIR = $(eval $(call MAKE_DIR_F,$(1)))
define MAKE_DIR_F
# get rid of irregularities in $(1) such as ..
MAKE_DIR_CANON := $(abspath $(1))
# depend on that canonical version
$(1): $$(filter-out $(1),$$(MAKE_DIR_CANON))
# iterate from root to $1 in the function MAKE_DIR_I
# depend each directory in turn on the parent
MAKE_DIR_I_PARENT := /
$$(foreach dir,$$(subst /, ,$$(MAKE_DIR_CANON)),$$(eval $$(call
MAKE_DIR_I,$$(dir))))
endef
########################################
# collect make directory targets for sorting later
########################################
MAKE_DIRS :=
########################################
# one itaration in MAKE_DIR_F
#
# add one level directory name $(1) to make the current dir global
# $(MAKE_DIR_I_CURR)
# depend that on the global parent $(MAKE_DIR_I_PARENT)
# and add that to make directory targets
########################################
define MAKE_DIR_I
MAKE_DIR_I_CURR := $$(MAKE_DIR_I_PARENT)$(1)
$$(MAKE_DIR_I_CURR): $$(MAKE_DIR_I_PARENT)
MAKE_DIRS += $$(MAKE_DIR_I_CURR)
# make global parent for the next iteration
MAKE_DIR_I_PARENT := $$(MAKE_DIR_I_CURR)/
endef
########################################
# make dirs without dup rules
########################################
$(sort $(MAKE_DIRS)):
mkdir $@
----- Original Message ----
From: Mark Galeck (CW) <address@hidden>
To: "address@hidden" <address@hidden>
Well, OK, I tried this, but does not work deeper than 1 level of directories, I
guess because the chain of implicit rules does not apply (or something of that
sort)
.PRECIOUS: %/.
.SECONDEXPANSION:
%/.: $$(dir $$*).
mkdir $*