As commented by others, but you can explicitly put a dependency to the $(ODIR)
directory (it must be created before any dependent files ---compilation):
$(OBJS): $(ODIR)
$(ODIR):
mkdir -p $@
This will ensure you have created the $(ODIR)
directory before any dependent files (any *.o
file) and that it will be created only once.
The final contents of your Makefile should be as this:
CC = gcc
CFLAGS = -Wall -g
DEPS = ex14.h
ODIR=obj
_OBJ=ex14.o main.o
OBJ=$(patsubst %,$(ODIR)/%,$(_OBJ))
all: ex14
$(ODIR)/%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $@ $<
ex14: $(OBJ)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f ex14 $(ODIR)*.o
rm -rf $(ODIR)
$(OBJ): $(ODIR)
$(ODIR):
mkdir -p $@
EDIT 2
After posting the correct rule I found some errors in the $(patsubst)
variable expansion, that made make to fail when not everything was erased.
Following is a correct, optimized Makefile:
$ cat Makefile
CC = gcc
CFLAGS = -Wall -g
DEPS = ex14.h
ODIR=obj
OBJS=ex14.o main.o
POBJS=$(foreach i,$(OBJS),$(ODIR)/$(i))
LIBS= # for example: -lm for math library.
.PHONY: all ex14 clean
$(ODIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
all: ex14
ex14: $(POBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(POBJS) $(LIBS)
clean:
rm -rf $(ODIR)
$(POBJS): $(ODIR) $(DEPS)
$(ODIR):
mkdir -p $@
putting the dependency on $(DEPS)
in the
$(OBJS): $(ODIR) $(DEPS)
makes the automatic default dependency rule for .c -> .o
files valid, and not needed anymore in the makefile. Also, I have used P
prefix to mean pathed file in POBJS
against OBJS
(which is the plain list of object files) Also removing recursively the objs
subdirectory makes unnecessary to remove the object files first, and then the subdirectory (only the last command is needed) Also, when linking, it is common use, to pass the compiler the $(LDFLAGS)
for it to pass them to the linker. And finally, if you have some libraries to include at the end, just use a $(LIBS)
library (not needed for your sample).
As stated in one of the comments, the compilation of just one source file makes the $(ODIR)
directory to be touched, and all the other files to be out of date, and this will make all the files but the one just compiled to be compiled next time. There's no solution to this problem as there's a circular dependency on this (the objects depend on the directory to exist, and the directory is touched on each compilation which makes the dependency to be triggered again for all the files compiled before the last one) The only possible solution to this problem is to eliminate the dependency on the directory and construct it by hand before calling make
.
Berkeley make (pmake
or bmake
, it depends) has a workaround to this problem, by allowing you to define a .BEGIN
dependency, that is to be solved before any other work. You can create the directory there. I think GNU make doesn't have this feature:
.BEGIN:
mkdir -p $(ODIR)
But this is out of scope for this question that is directed to GNU make.