Jeff Learman
Jeff Learman

Reputation: 3287

makefile: compile from different src dirs to separate obj dir

This is for a unit test makefile. The directory structure, already established, is:

srca/ contains sources
srcb/ contains sources
test/ contains UT sources and Makefile
test/Debug is to contain objects

I can get it to work if I don't care that objects (.o, .gcda, etc.) are created in Test, with the following:

.PHONY = all build
all: build
vpath %.c ../srca ../srcb

SRC = \
    ../srca/a.c \
    ../srcb/b.c \
    test.c

OBJDIR=
OBJ = $(addprefix $(OBJDIR),$(notdir $(patsubst %.c, %.o , $(SRC))))

$(OBJ): $(OBJDIR)/%.o : %.c

Debug/UnitTest.exe: $(OBJ)
    gcc $(OBJ) -o ./Debug/UnitTest.exe

build: Debug/UnitTest.exe

When I try to build objects into Debug by setting OBJDIR to Debug/, I get errors like the following:

test1.mk:16: target `Debug/a.o' doesn't match the target pattern

The line that sets OBJ was lifted from another stackoverflow post and I confess I don't follow it, but it works in the above case. Also, the following line isn't needed when OBJDIR is empty:

$(OBJ): $(OBJDIR)/%.o : %.c

but if I omit it when OBJDIR is "Debug/", I get

make: *** No rule to make target `Debug/a.o', needed by `Debug/UnitTest.exe'.  Stop.

So, that rule helps when OBJDIR is not empty, but not quite enough.

Upvotes: 0

Views: 259

Answers (2)

Jeff Learman
Jeff Learman

Reputation: 3287

For the record, here is the working makefile:

.PHONY = all build
all: build
vpath %.c ../srca ../srcb

SRC = \
    ../srca/a.c \
    ../srcb/b.c \
    test.c

OBJDIR=Debug/
OBJ = $(addprefix $(OBJDIR),$(notdir $(patsubst %.c,%.o,$(SRC))))

$(OBJ): $(OBJDIR)%.o : %.c
    gcc -c $< -o $@

Debug/UnitTest.exe: $(OBJ)
    gcc $(OBJ) -o ./Debug/UnitTest.exe

build: Debug/UnitTest.exe

Upvotes: 0

Renaud Pacalet
Renaud Pacalet

Reputation: 29015

Your definition of OBJDIR (empty string), OBJ (patsubst) and your %.o: %.c rule are the main causes of your problem. In your example the value of OBJ is:

a.o b.o test.o

And your %.o: %.c rule expands as:

a.o b.o test.o: /%.o : %.c

Indeed, a.o b.o test.o do not match the /%.o pattern. You should replace your definitions of OBJDIR and OBJ by:

OBJDIR = .
OBJ = $(addprefix $(OBJDIR)/,$(notdir $(patsubst %.c,%.o,$(SRC))))

Note that I also removed the spaces in the call of the patsubst function: with make spaces must be handled carefully. Avoid putting spaces where they are not needed, you will avoid subtle bugs, difficult to understand and fix, due to leading or trailing spaces in variable values.

If OBJDIR is set to something else than ., e.g. Debug, you will encounter another issue: implicit rules do not work like this and you will have to add an explicit recipe:

$(OBJ): $(OBJDIR)/%.o : %.c
    gcc -c $< -o $@

Upvotes: 1

Related Questions