Reputation:
The GNU standard says it is a good idea to not use the -p
command for mkdir
:
For example, don’t use ‘mkdir -p’, convenient as it may be, because a few systems don’t support it at all and with others, it is not safe for parallel execution
I would like to adhere to this standard and thus I am running into a problem in my Makefile.
I am recursively compiling all C sources from all directories within the src
directory and would like to place them inside the obj
directory. The same directory structure is mirrored inside the obj
directory, however these directories do not initially exist.
I could very easily do mkdir -p $(@D)
to create my directories, but following GNU's standard, I cannot do this, which brings me to my question: How can I work around this in a Makefile?
My Makefile below:
SRCDIR=src
OBJDIR=obj
CC=cc
CFLAGS=
CFLAGS=-g -O2 -pedantic -Wall
ALL_CFLAGS=-std=c89 $(CFLAGS)
# Copied from https://stackoverflow.com/questions/2483182/recursive-wildcards-in-gnu-make/18258352#18258352
rwildcard=$(foreach d, $(wildcard $1/*), $(call rwildcard, $d, $2) $(filter $(subst *, %, $2), $d))
SOURCES=$(call rwildcard, $(SRCDIR), *.c)
OBJECTS=$(subst $(SRCDIR),$(OBJDIR),$(SOURCES:.c=.o))
all: $(OBJECTS)
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) $(ALL_CFLAGS) -c -o $@ $<
Upvotes: 2
Views: 739
Reputation: 15503
You could just use make dependencies.
Drop a file, .created
say, in each folder.
Build the .created
files with a pattern rule,
which naturally creates the folder as a side effect.
SOURCES=$(call rwildcard, $(SRCDIR), *.c)
OBJECTS=$(subst $(SRCDIR),$(OBJDIR),$(SOURCES:.c=.o))
.PHONY: all
all: $(OBJECTS)
%/.created:
mkdir -p ${@D}
touch $@
$(OBJDIR)/%.o: $(SRCDIR)/%.c | ${OBJDIR}/.created
$(CC) $(ALL_CFLAGS) -c -o $@ $<
It means that folders are created once by make, and only when they are needed. Parallel safe too.
[This is just a sketch.
Your substitution doesn't look right to me
— I assume you have no src/
folder under another src/
folder(???),
and your %.o
pattern is not quite right.]
Upvotes: 0
Reputation: 33727
The GNU standards are outdated in many places. This appears to be one of these places.
Nowadays, mkdir -p
is part of POSIX. It is not even a recent invention because it came from System V.
Since your makefile assumes that the C compiler is GCC (or at least has a GCC-compatible command line syntax), you might as well assume that mkdir -p
works. If you want users an easy way to override it if it does not for them, you could add this:
MKDIR_P = mkdir -p
and use $(MKDIR_P)
in recipes, in place of mkdir -p
.
But all this really shouldn't be necessary. Even GNU's supposedly-portable mkinstalldirs
script has been using mkdir -p
for a long, long time.
Upvotes: 1