[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Has anyone ever tried this technique for creating target parent director

From: Bryan Ischo
Subject: Has anyone ever tried this technique for creating target parent directories?
Date: Sat, 19 Nov 2011 22:43:03 -0800
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:8.0) Gecko/20111108 Thunderbird/8.0

I tried many iterations on creating the most "automatic" way that I could think of for creating target directories in my Makefile, having read about the pros and cons of various solutions suggested on the web and also having seen different techniques used in practice in the makefiles of working projects.

What I wanted was some way to have the parent directory of every target created if it didn't already exist (using mkdir -p style so that all intermediate directories are created as well), and I wanted it to not require special incantations on the part of other makefiles in my system that relied on my base set of include'd rules.

What I came up with is this (simplified form):

.PRECIOUS: %/../.dir
$(if $(wildcard $(dir $(patsubst %/../.dir,%,$@))),,$(shell mkdir -p $(dir $(patsubst %/../.dir,%,$@))))

For this rule, the directory in question is defined as the parent directory of a file called '.dir' located in the same directory as a target. So for example if I have a target foo/bar/obj/foo.o, then I would invoke this rule by creating a prerequisite of foo.o of foo/bar/obj/foo.o/../.bar. As you can see if we fold out the .. then we get a prerequisite file of foo/bar/obj/.bar.

What the commands do is to check to see if the wildcard function finds that the directory containing this .dir file, which is the parent directory of the target that we want to create the parent directory, exists or not, and only if it does not exist, then we call mkdir on the parent directory.

Then I use this target like this in all of my pattern rules:

%.o: %.o/../.dir %.c
  gcc -o $@ -c $(filter .c $^)

The result is that whenever the parent directory of a target object file does not exist, it is first created.

This works great, and my un-simplified version, which I will not present here, works on MSDOS style cmd shells as well as on Unix (the un-simplified version just uses a variable to invoke "mkdir -p" that is appropriate for MSDOS vs Unix and also does substitution of / with \ in the directory name passed to mkdir).

A nice aspect to this is that the .dir file never actually has to be created; once the .o file is created then it doesn't matter whether the .dir file was ever created, make ceases to care about the .dir file. So subsequent builds don't do any extra work of checking for directory existence or trying to re-create the directory. I expect that if a .o file fails to compile for some reason, then even if the parent directory of the .o file was successfully created, then my rule will be re-invoked; but it will do nothing because the wildcard will match the target directory that was already created.

The .PRECIOUS is necessary, otherwise make will produce lots of unnecessary error messages about not being able to remove the never-created .dir files; the make will not fail but the errors are ugly and annoying.

The reason that I like my solution is that it doesn't require that any of the other rules that I create add mkdir commands to their list of commands; they just create a prerequisite of %/../.dir and the mkdir is automagically taken care of.

One annoyance of this solution is that your list of prerequisites gets a .dir file in it, which means that you can't use $^ or $< unless you don't mind passing the .dir file to your command (and there are very few commands which can tolerate this). So you have to use, e.g. "$(filter-out %/../.dir,$^).

I have seen alot of suggestions for how to handle directory creation for targets, but never the one that I have come up with. Has anyone done this previously?

Also - I am far from a make expert. Is there anything suboptimal or ugly about my solution that could be made tidier?


reply via email to

[Prev in Thread] Current Thread [Next in Thread]