user5549921
user5549921

Reputation:

Creating subdirectories in Makefile without mkdir -p

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

Answers (2)

bobbogo
bobbogo

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

Florian Weimer
Florian Weimer

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

Related Questions