Makefile foreach removes path from previous item

Viewed 23

I'm having a bit of a problem trying to use a foreach in a makefile (probably due to a noobness problem?)

I have a project with this structure

Project_root
+- Makefile
+- main.c
+- main.h
+- Module_1
|  +- src
|  |  +- unit_test
|  |  |  +- Module_1_test.c
|  |  |  +- Module_1_test.h
|  |  +- Module_1.c
|  |  +- Module_1.h
+- Module_2
|  +- src
|  |  +- unit_test
|  |  |  +- Module_2_test.c
|  |  |  +- Module_2_test.h
|  |  +- Module_2.c
|  |  +- Module_2.h
...

The objective is to have each module encapsulated and then have a makefile like so:

TARGET_LIBS += Module_1
TARGET_LIBS += Module_2

...

DEPS = ${foreach SRC, $(basename $(wildcard $(TARGET_LIBS)/src/*.c)), $(addsuffix .o, $(SRC))}
DEPS_TEST = ${foreach SRC, $(basename $(wildcard $(TARGET_LIBS)/src/unit_test/*.c)), $(addsuffix .o, $(SRC))}
DEPS_PATH = ${foreach LIB, $(TARGET_LIBS), $(LIB)/src}

all: $(DEPS) main.o
    gcc $(CFLAGS) main.o $(DEPS) $(CLIBS) -o main

test: $(DEPS) main.o
    gcc $(CFLAGS) main.o $(DEPS) $(CLIBS) -o main

...

$(DEPS):
    gcc $(CFLAGS) -c $(addsuffix .c, $(basename $(DEPS))) -I $(DEPS_PATH)

For a simple program where we use 1 module I have: Makefile:

TARGET_LIBS += Module_1

...

Variables:

TARGET_LIBS -> Module_1
DEPS -> Module_1/src/Module_1.o
DEPS_TEST -> Module_1/src/unit_test/Module_1_test.o
DEPS_PATH -> Module_1/src

But when using more modules, by having more "TARGET_LIBS += ..." lines, I get this problem:

Makefile:

TARGET_LIBS += Module_1
TARGET_LIBS += Module_2

...

Variables:

TARGET_LIBS -> Module_1 Module_2
DEPS -> Module_1.o Module_2/src/Module_2.o
DEPS_TEST -> Module_1_test.o Module_2/src/unit_test/Module_2_test.o
DEPS_PATH -> Module_1/src Module_2/src

By having 2 modules, the first module to be added in the makefile loses the path in DEPS. DEPS should be 'Module_1/src/Module_1.o Module_2/src/Module_2.o', but I have 'Module_1.o Module_2/src/Module_2.o'.

Is there something wrong in the makefile? Am I making some wrong assumption?

I'd appreciate any "You should do this instead" type of answers, but if someone can explain the "Why" this is not working so I don't get the same problem again... It would be the perfect answer

Thanks in advance

1 Answers

Well, it's not too hard to figure out. Let's see what you have:

$(wildcard $(TARGET_LIBS)/src/*.c)

OK, well, what is TARGET_LIBS?

TARGET_LIBS += Module_1
TARGET_LIBS += Module_2

so the value of TARGET_LIBS is Module_1 Module_2. So what does that wildcard function expand to?

$(wildcard Module_1 Module_2/src/*.c)

and what is your output?

Module_1 Module_2/src/Module_2.c

just as you'd expect.

Simply adding some extra text after a variable doesn't magically cause that extra text to be appended to every word in that variable... when working with variables that contain multiple words you need to use functions that modify all the words.

I would write it like this:

DEPS := $(patsubst %.c,%.o,$(wildcard $(addsuffix /src/*.c,$(TARGET_LIBS))))
Related