34
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?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
ant2009
  • 27,094
  • 154
  • 411
  • 609

3 Answers3

30

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 $@
Beta
  • 96,650
  • 16
  • 149
  • 150
  • 1
    What about for creating a shared library? I ran across a site claiming I need the `-c` switch for creating a shared library, but using this prevents me from using `-o`. And currently, make is creating the object files just in the root project dir. My folder structure is: `src/lib/*`, and I want obj files to be generated in `obj/lib/*` The gcc command is: `g++ -std=c++11 -g -I./include -fPIC -Wall -c ./src/lib/Source1.cpp ./src/lib/Source2.cpp` – krb686 Dec 30 '15 at 02:03
  • 1
    Ok, I got it. Was trying to compile multiple objects dependent on multiple sources. I replaced with your static pattern rule and automatic variables `$<` and `$@` and it works like a charm. Also don't know why gcc complains and says you can't use `-c` with `-o` but you certainly can. – krb686 Dec 30 '15 at 02:26
7

Use gcc's -o option to write the output file to a particular location. For instance, you could say:

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

Unfortunately, there's a problem with this line: if there is more than one source file in $(SOURCES), it won't work, since $(OBJECTS) will also contain multiple file names, and the -o option only binds to the first argument.

A way to compile each file in a list of source code files is to use implicit rules. In gmake, you would write:

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

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

where $< is replaced with name of the input file and $@ is replaced with the name out the output file.

radical7
  • 8,957
  • 3
  • 24
  • 33
  • 1
    @Beta Sorry, what is the "This" you are referring to? – radical7 Feb 01 '13 at 07:10
  • 1
    Your solution, the "proper way". Try it with more than one source file and you'll see what I mean. – Beta Feb 01 '13 at 07:17
  • 1
    @Beta my approach works on the systems I've tested it on. If `$(OBJECTS)` contains multiple filename each of which can be driver from a `.c` file, this idiom will generate each `.o` in turn. I've used this all over the place, so I'd certainly be interested in which operating system and make you tried it on. – radical7 Dec 28 '13 at 17:22
  • 1
    Did you check to see whether it handles dependencies correctly? Did you read my answer, the part about *each* object depending on *all* sources? – Beta Dec 29 '13 at 21:02
  • 1
    I see your point; with OBJECTS depending on SOURCES, object files may be regenerated more often than necessary, but it still generates a correct solution, regardless of how many source files at there (assuming that all the sources are for a single executable). – radical7 Dec 29 '13 at 22:43
2

I solved this request and here is my Makefile and directory tree.

PROJECT := main.exe

DIR_SRC += .
DIR_SRC += ./src

DIR_INC += -lpthread 
DIR_INC += -I./inc 
DIR_INC += $(addprefix -I, $(DIR_SRC))

SRC_C += $(wildcard $(addsuffix /*.c, $(DIR_SRC)))
#OBJ := $(filter %.o, $(SRC_C:.c=.o))
OBJ := $(patsubst %.c, %.o, $(SRC_C))
EXE := $(PROJECT)

CC_PREFIX := 
CC := $(CC_PREFIX)gcc
CFLAG = 
CLIB = -L .

.PHONY:all

all:$(OBJ) $(EXE)

%.o: %.c
    $(CC) $(CFLAG) $(DIR_INC) -c $< -o $@ 

$(EXE): $(OBJ)
    $(CC) $(CFLAG) $(CLIB) $(OBJ) -o $@ 

clean:
    rm -r $(EXE) $(OBJ) 

See my directory tree:

enter image description here

Jason C
  • 38,729
  • 14
  • 126
  • 182
Mou
  • 145
  • 1
  • 6