Getting make to create object files in a specific directory

ant2009 picture ant2009 · Feb 1, 2013 · Viewed 82.5k times · Source
GNU Make 3.82
gcc 4.7.2
c89

I have the following make file:

INC_PATH=-I/home/dev_tools/apr/include/apr-1
LIB_PATH=-L/home/dev_tools/apr/lib
LIBS=-lapr-1 -laprutil-1
RUNTIME_PATH=-Wl,-rpath,/home/dev_tools/apr/lib
CC=gcc
CFLAGS=-Wall -Wextra -g -m32 -O2 -D_DEBUG -D_THREAD_SAFE -D_REENTRANT -D_LARGEFILE64_SOURCE $(INC_PATH)
SOURCES=$(wildcard src/*.c)
OBJECTS=$(patsubst %.c, %.o, $(SOURCES))

EXECUTABLE=bin/to

all:    build $(EXECUTABLE)

$(EXECUTABLE):  $(OBJECTS)
    $(CC) $(CFLAGS) -o $@ $(RUNTIME_PATH) $(OBJECTS) $(LIB_PATH) $(LIBS)

$(OBJECTS): $(SOURCES)
    $(CC) $(CFLAGS) -c $(SOURCES) $(LIB_PATH) $(LIBS)

build:
    @mkdir -p bin

clean:
    rm -rf $(EXECUTABLE) $(OBJECTS) bin
    find . -name "*~" -exec rm {} \;
    find . -name "*.o" -exec rm {} \;

My directory structure is like this project/src project/bin. My Makefile is in the project (root) folder, and all my *.h and *.c are in the src directory. Currently I have only one source file called timeout.c

I get this error:

gcc: error: src/timeout.o: No such file or directory

I have used this to get all the source files:

SOURCES=$(wildcard src/*.c)

And the object files:

OBJECTS=$(patsubst %.c, %.o, $(SOURCES))

However, the make seems to create the object file in the project root folder where the Makefile is. Should it not put it in the src directory?

Answer

Beta picture Beta · Feb 1, 2013

You have two problems in this rule (well, three):

$(OBJECTS): $(SOURCES)
    $(CC) $(CFLAGS) -c $(SOURCES) $(LIB_PATH) $(LIBS)

You haven't noticed yet, but the rule makes each object dependent on all sources, and tries to build that way. Not a problem as long as you have only one source. Easy to fix with a static pattern rule and an automatic variable:

$(OBJECTS): src/%.o : src/%.c
    $(CC) $(CFLAGS) -c $< $(LIB_PATH) $(LIBS)

Also, the command ("$(CC)...") doesn't specify an output file name, so gcc will infer it from the source file name; if you give it src/timeout.c, it will produce timeout.o (in the working directory, project/). So you should specify the desired path to the output file. Easy to do with another automatic variable:

$(OBJECTS): src/%.o : src/%.c
    $(CC) $(CFLAGS) -c $< $(LIB_PATH) $(LIBS) -o $@