7
votes

The directory structure of my C++ project is

/..
   makefile     <- the makefile is in root
   /include     <- subdirectory that has to be included while compiling
   /obj         <- target place for all *.o and final executable
   /src         <- sources

And my current makefile is:

CC=g++
CFLAGS=-c -Wall -std=c++11

INC=-Iinclude
SRC=src
TGT=obj

all: myapp

myapp: myapp.o
    $(CC) $(TGT)/myapp.o -o $(TGT)/myapp

myapp.o:
    $(CC) $(CFLAGS) $(INC) $(SRC)/myapp.cpp -o $(TGT)/myapp.o

clean:
    rm -rf $(TGT)
    mkdir $(TGT)

This worked for my first file. I am a total makefile novice - please help me compile all files under the /src directory and link them to an executable in /obj directory.

the makefile has to work under Windows, I am using MinGW and MSYS

2

2 Answers

5
votes

Add a list of your source files:

SOURCES = $(wildcard $(SRC)/*.cpp)

and a list of corresponding object files:

OBJS = $(addprefix $(TGT)/, $(notdir $(SOURCES:.cpp=.o)))

and the target executable:

$(TGT)/myapp: $(OBJS)
    $(CXX) $(LDFLAGS) $(OBJS) -o $@

The rule for building the objects:

$(TGT)/%.o: $(SRC)/%.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@

Now you must specify are the options for g++:

INCLUDES = -Iinclude
CXXFLAGS = -Wall -std=c++11 $(INCLUDES)

And everything together:

SRC=src
TGT=obj
INCLUDES = -Iinclude
CXXFLAGS = -Wall -std=c++11 $(INCLUDES)
SOURCES = $(wildcard $(SRC)/*.cpp)
OBJS = $(addprefix $(TGT)/, $(notdir $(SOURCES:.cpp=.o)))

$(TGT)/%.o: $(SRC)/%.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@

$(TGT)/myapp: $(OBJS)
    $(CXX) $(LDFLAGS) $(OBJS) -o $@

It is important, that in front of $(CXX) ... there must be a "tab" character, not spaces.

1
votes

You can use VPATH for separating source and object files:

src/myapp.c
obj/Makefile

Take your existing Makefile, move it into obj/, omit references to $(TGT) and $(SRC) and add the following:

VPATH=../src

Note that if you are trying to do multi-architecture builds, VPATH is not ideal.


BTW, you're not capitalizing on builtin rules. Where you have

CC=g++
CFLAGS=-c -Wall -std=c++11
myapp: myapp.o
    $(CC) $(TGT)/myapp.o -o $(TGT)/myapp

myapp.o:
    $(CC) $(CFLAGS) $(INC) $(SRC)/myapp.cpp -o $(TGT)/myapp.o

you could instead use:

CXXFLAGS=-Wall -std=c++11
CXXFLAGS+=$(INC)
LDLIBS+=-lstdc++

myapp: myapp.o

So, to sum it all up, your new obj/Makefile should look like this:

VPATH=../src
INC=-I../include
CXXFLAGS=-Wall -std=c++11
CXXFLAGS+=$(INC)
LDLIBS+=-lstdc++

myapp: myapp.o

You can create another Makefile up from obj/ to recurse down into this new one, if necessary:

all: obj/myapp

obj/myapp:
    mklink obj/Makefile ../Makefile
    $(MAKE) --directory=obj/