Romsdal
Romsdal

Reputation: 43

Makefile builds source files from different directories into the same object directory

I have a c project with directory layout like this

src1
    -a.c
    -b.c
src2
    -c.c
    -d.c
objects

I'm trying to compile a/b/c/d into objects files and saved them into objects directory and here is part of my Makefile.

src1 = src1/
src1 = src2/
obj = objects/
src1_files = a.c b.c
src2_files = c.c d.c
source_files = $(addprefix $(src1), $(src1_files)) $(addprefix $(src1), $(src2_files)) 
objects := $(addprefix $(obj), $(src1_files:.c=.o)) $(addprefix $(obj), $(src2_files:.c=.o))

$(obj)%.o: $(source_files)
    $(CC) $(CFLAGS) -c $< -o $@

all: $(objects)

However when I try to run make, I got the following.

gcc -Wall -c src1/a.c -o objects/a.o
gcc -Wall -c src1/a.c -o objects/b.o
gcc -Wall -c src1/a.c -o objects/c.o
gcc -Wall -c src1/a.c -o objects/d.o

Anyone knows why is it doing that?

Upvotes: 3

Views: 309

Answers (2)

Scheff&#39;s Cat
Scheff&#39;s Cat

Reputation: 20141

After having read the answer of Felix Palmen, especially the last sentence

If you really want the objects directly in your objects directory, you need two pattern rules, one matching the sources in src1 and one matching the sources in src2.

I modified the Makefile accordingly (out of curiosity):

src1 = src1/
src2 = src2/
obj = objects/
src1_files = a.c b.c
src2_files = c.c d.c
source_files = $(addprefix $(src1), $(src1_files)) $(addprefix $(src2), $(src2_files)) 
objects := $(addprefix $(obj), $(src1_files:.c=.o)) $(addprefix $(obj), $(src2_files:.c=.o))

$(obj)%.o: src1/%.c
    $(CC) $(CFLAGS) -c $< -o $@

$(obj)%.o: src2/%.c
    $(CC) $(CFLAGS) -c $< -o $@

all: $(objects)

I tested in bash on cygwin:

$ mkdir src1 src2 objects

$ touch src1/a.c src1/b.c src2/c.c src2/d.c

$ make
cc  -c src1/a.c -o objects/a.o
cc  -c src1/b.c -o objects/b.o
cc  -c src2/c.c -o objects/c.o
cc  -c src2/d.c -o objects/d.o

$ 

...and it worked.

(I left out the detail about building the objects directory – just created it manually).

Upvotes: 3

user2371524
user2371524

Reputation:

This is not how pattern rules work. When trying to build an object file with your rule, make tries to replace a % in the prerequisite with whatever matches the % in your target -- but your prerequisite doesn't contain a %, so it's just taken literally. In your recipe, you just take the first one from the prerequisites list ($<), which is always the same.

The easiest thing to do is to just replicate the directory structure below your object directory, this is what most Makefiles will actually do. Something like this:

objects := $(addprefix $(obj), $(source_files:.c=.o))

$(obj)%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

You will need to make sure the directories exist, e.g. like this (untested):

objdirs := $(obj)$(src1) $(obj)$(src2)

$(objdirs):
    mkdir -p $@

$(obj)%.o: %.c | $(objdirs)
    $(CC) $(CFLAGS) -c $< -o $@

If you really want the objects directly in your objects directory, you need two pattern rules, one matching the sources in src1 and one matching the sources in src2.

Upvotes: 2

Related Questions