Max Max - 24 days ago 7
C Question

Makefile : Automatically compile all c files, keeping .o files in separate folder

I've been searching for this for hours but somehow I still haven't found something that works for me.

What I have is a directory with 3 sub-directories. src/ for .c and .h files, bin/ where the compiled executable is supposed to go and obj/ where I want the .obj files to go.

Now I want the makefile to compile every .c file from src (without me having to list them all in the makefile) and put the .o files in obj and the executable built from foo.c saved as bin/foo.

Can someone help me out? Whenever I use wildcards, make complains about rules not being there and when I use implicit rules, it doesn't put the object files in a separate folder.

Answer

To build foo.o from foo.c, locally:

foo.o: foo.c
    $(CC) -c $< -o $@

To do the same, but with any needed header files in src/:

SRC := src

foo.o: foo.c
    $(CC) -I$(SRC) -c $< -o $@

To do the same, but with the source file in src/:

SRC := src

foo.o: $(SRC)/foo.c
    $(CC) -I$(SRC) -c $< -o $@

To do that, but put the object file in obj/:

SRC := src
OBJ := obj

$(OBJ)/foo.o: $(SRC)/foo.c
    $(CC) -I$(SRC) -c $< -o $@

A pattern rule that will do that for any such object file (obj/foo.o, obj/bar.o, ...):

SRC := src
OBJ := obj

$(OBJ)/%.o: $(SRC)/%.c
    $(CC) -I$(SRC) -c $< -o $@

To create the list of desired objects:

SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))

And a rule to cover them all:

all: $(OBJECTS)

Putting it all together:

SRC := src
OBJ := obj

SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))

all: $(OBJECTS)

$(OBJ)/%.o: $(SRC)/%.c
    $(CC) -I$(SRC) -c $< -o $@

Note that this has one big shortcoming: is does not track dependencies on header files. This can be done automatically, but it's a subtle trick; it can wait until you've mastered this much.