user3826752 user3826752 - 1 month ago 7
C Question

How to Compile all C file into Object and place it in subdirectories

How to compile all C files into object files and place them in subdirectories?

I have three directories:


  1. usr
    - where locate main.c

  2. sources1
    - where locate init_var1.c and init_var2.c

  3. include
    - where locate header files

  4. obj
    - at this directory will be locate object file from c file in 1 and 2 directories.



I write this
makefile
:

CC=gcc

O_DIR = ./../obj
I_DIR = ./../include

SOURCES := $(wildcard *.c)
OBJECTS := $(SOURCES:.c=.o)

OBJECTS := $(addprefix $(O_DIR)/,$(OBJECTS))

all: $(OBJECTS)

$(OBJECTS): $(SOURCES)
$(CC) -c -I$(I_DIR) $< -o $@


but the output is

make[1]: enter directory «/home/alexey/exercise/ex_makefile/source»
gcc -c -I./../include init_var1.c -o ../obj/init_var1.o
gcc -c -I./../include init_var1.c -o ../obj/init_var2.o
make[1]: out from directory «/home/alexey/exercise/ex_makefile/source»


but I need

make[1]: enter directory «/home/alexey/exercise/ex_makefile/source»
gcc -c -I./../include init_var1.c -o ../obj/init_var1.o
gcc -c -I./../include init_var2.c -o ../obj/init_var2.o
make[1]: out from directory «/home/alexey/exercise/ex_makefile/source»


Please help, how to do it?

Answer

You are setting SOURCES to equal the wildcard expansion of *.c. This expands to a list of all your .c files and therefore, the line

$(OBJECTS): $(SOURCES)

expands to something like

a.o b.o c.o ... : a.c b.c c.c ...

Note that this is wrong semantically since each of your object files shouldn't depend on all the source files.

Since the automatic variable $< denotes the name of the first prerequisite, each of the object files a.o, b.o, c.o and so forth gets created using the source file a.c.


What you want instead is a pattern rule:

You define an implicit rule by writing a pattern rule. A pattern rule looks like an ordinary rule, except that its target contains the character ‘%’ (exactly one of them). The target is considered a pattern for matching file names; the ‘%’ can match any nonempty substring, while other characters match only themselves.

This will allow you to make each of your object files depend only on their corresponding source file (and it will also make $< expand to the correct file since the first prerequisite will be the only prerequisite). Therefore, your rule should look like this:

%.o : %.c
    $(CC) -c -I$(I_DIR) $< -o $@

In fact, the examples page for pattern rules of the GNU make manual has an example very similar to your rule.