Reputation: 193
I've seen a few approaches to making output directories in Make. These include making all directories ahead of time outside of any rule, and making an object's destination directory as part of the object's rule. Both of these approaches involve making directories that likely already exist.
Am I missing any gotchas or drawbacks that explain why I haven't seen the below approach?
.SECONDEXPANSION:
$(OBJDIR)%.o: %.c | $$(@D)/
# Compile command
.PRECIOUS: %/
%/:
# mkdir Command
Upvotes: 2
Views: 111
Reputation:
The problem with directories is that (contrary to any other target) you don't care for their timestamp, you only need them to exist. Many Makefiles get directories somehow wrong, and creating them over and over again is what you observe, so make
will never detect "Nothing to be done for ...".
In fact, the only thing you need for correct handling of directories with GNU make is an "order only dependency", like shown in your example. The trailing slash normally isn't needed (you seem to use it in order to have a pattern rule, I'm not sure whether this works), and you don't need .PRECIOUS
either. Your trick with .SECONDEXPANSION
looks quite neat, I guess this will work, given the pattern rule indeed works that way (didn't try).
For an alternative, most Makefiles that handle directories correctly take a simpler approach by concatenating all needed output directories for a rule in a single variable and use this variable as a target for another rule, e.g. like in this simplified example:
MODULES:=src/main
OBJDIR?=obj
OBJS:=$(addprefix $(OBJDIR)/,$(addsuffix .c,$(MODULES)))
DIRS:=$(sort $(addprefix $(OBJDIR)/,$(dir $(OBJS))))
TARGET:= myprogram
all: $(TARGET)
myprogram: $(OBJS)
$(CC) -o$@ $^
$(DIRS):
mkdir -p $(DIRS)
$(OBJDIR)/%.o: %.c Makefile | $(DIRS)
$(CC) -c -o$@ $<
clean:
rm -fr $(OBJDIR)
.PHONY: all clean
Upvotes: 0
Reputation: 37787
make
is very good at dealing with files. make
is not very good at dealing with directories.
So treating directories as implementation detail internal to the target rule makes sense, because then make
never has to consider the directory at all:
MKDIR_P = mkdir -p
$(objdir)%.o: %.c
@$(MKDIR_P) $(@D)
$(COMPILE.c) -o $@ -c $<
Note that the processing and IO required for the mkdir -p
can be neglected next to the processing and IO required for the compilation.
Upvotes: 1