0

I'm writing a Makefile for my project. The project is something like this:

 config.mk - variables like CC, CFLAGS, PREFIX, etc.
 obj
 src
  |--- include
  |--- foo1
  |     |--- 1.c
  |     |--- 2.c
  |     L--- unwanted1.c
  L--- foo2
        |--- bar1
        |     |---3.c
        |     |---4.c
        |     |---unwanted2.c
        |     L---unwanted3.c
        |--- bar2
              |---5.c
              L---6.c

I wanted to exclude the unwanted .c files (they were used in a different part of the build process), build them then put the created object files in obj. But I don't know how to build them yet. This is what I've been able to write (and worked):

# Compiler setting are defined here:
include config.mk     

SRCS = src/foo1/1.c src/foo1/2.c \
       src/foo2/bar1/3.c src/foo2/bar1/4.c \
       src/foo2/bar2/5.c src/foo2/bar2/5.c
OBJS = $(addprefix obj/,$(notdir $(SRCS:.c=.o)))

But I don't know how to write the building part. Answers I've found used %.c and %.o, which is impossible in this case. I tried writing it like this:

$(OBJS): $(SRCS)
        ${CC} -fPIC -c -Isrc/include ${CFLAGS} -o $@ $<
lib: $(OBJS)
        ${CC} -shared -o lib.so -Wl,-soname="lib.so" $(OBJS)

But it didn't work. make: *** No rule to make target 'obj/bar1.o', needed by 'lib'. Stop.

How can I rewrite the building part to make it work?

Thanks in advance.

tch69
  • 11
  • 1
  • 2
  • I don't see any way you could get that error from the makefile you provided so there must be some mismatch between what you actually did and what you posted here. – MadScientist Oct 09 '22 at 13:22

1 Answers1

0

Your current attempt can't work because it expands to:

obj/1.o obj/2.o ... : src/foo1/1.c src/foo1/2.c ...

and make parses this exactly as if you'd written:

obj/1.o : src/foo1/1.c src/foo1/2.c ...
obj/2.o : src/foo1/1.c src/foo1/2.c ...
  ...

which not only will do the wrong thing (because $< is always the same file: src/foo1/1.c so you'll always compile the same file) but will rebuild all the object files whenever any object file changes.

First let me say, it's a bad idea to dump all your object files into a single directory. What if you have src/foo1/1.c and then you also create src/foo2/bar1/1.c? You're basically saying, yes I have a complex data structure for all my sources, but even so they all must have unique names. A better idea is to mirror the source structure in the object directory, then you just need this:

OBJS = $(patsubst %.c,obj/%.o,$(SRCS))

obj/%.o: %.c
        @mkdir -p $(@D)
        ${CC} -fPIC -c -Isrc/include ${CFLAGS} -o $@ $<

If you really, really want to put all .o's into a single directory the best way to do it is with VPATH:

VPATH = $(sort $(dir $(SRCS)))
OBJS = $(addprefix obj/,$(notdir $(SRCS:.c=.o)))

obj/%.o: %.c
        ${CC} -fPIC -c -Isrc/include ${CFLAGS} -o $@ $<
MadScientist
  • 92,819
  • 9
  • 109
  • 136