Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 925
Max Avatar asked Nov 15 '16 23:11

Max


People also ask

How do I use makefile to clean?

The Cleanup Rule clean: rm *.o prog3 This is an optional rule. It allows you to type 'make clean' at the command line to get rid of your object and executable files. Sometimes the compiler will link or compile files incorrectly and the only way to get a fresh start is to remove all the object and executable files.

Can you have two makefiles one folder?

If you use more than one ' -f ' or ' --file ' option, you can specify several makefiles. All the makefiles are effectively concatenated in the order specified. The default makefile names GNUmakefile , makefile and Makefile are not checked automatically if you specify ' -f ' or ' --file '.

What does all in makefile do?

This means that when you do a "make all", make always thinks that it needs to build it, and so executes all the commands for that target. Those commands will typically be ones that build all the end-products that the makefile knows about, but it could do anything.


1 Answers

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)
    $(CC) $^ -o $@

$(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.

like image 193
Beta Avatar answered Sep 20 '22 01:09

Beta