Lacoudasse
Lacoudasse

Reputation: 29

makefile: build .o files in another directory

Edit: This is the final Makefile, it build all .o files in build dir and produce one executable.

CXX         = g++
CXXFLAGS    = -g -Wall

SRC_DIR     = ./src
BUILD_DIR   = ./build
        
SRC         = $(wildcard $(SRC_DIR)/*.cpp)
OBJS        = $(SRC:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)
LIBS        = -lusb-1.0 -lpulse-simple -lpulse
EXEC        = AndroidMicLinux


all: $(EXEC)

$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cpp
    $(CXX) $(CXXFLAGS) -o $@ -c $<

$(EXEC) : $(OBJS)
    $(CXX) -o $(EXEC) $(OBJS) $(LIBS)

clean:
    rm -f $(OBJS) $(EXEC)

Upvotes: 1

Views: 785

Answers (1)

MadScientist
MadScientist

Reputation: 100836

There are many issues with this makefile. Most of them have to do with expansion of variables. If you simply visualize the expansion of variables you'll likely see the problems. Remember that make is just doing text substitution to expand variables. There's no "magic" happening here.

So for example:

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

Let's suppose that you have the files ./src/foo.cpp and ./src/bar.cpp. That means that $(SRC) will expand to those two files. Fine. Then you have:

OBJS    = $(BUILD_DIR)/$(notdir $(SRC:.cpp=.o))

How does this work? First we expand BUILD_DIR:

OBJS    = ./build/$(notdir $(SRC:.cpp=.o))

Then we expand $(SRC:.cpp=.o) which gives ./src/foo.o ./src/bar.o. Then the notdir is applied which gives foo.o bar.o. That's substituted for the function, so the result is:

OBJS    = ./build/foo.o bar.o

You can see this is wrong. You can't just stick a string before a function and expect that string to be appended to every word of the function! You need to explicitly tell make that you want to do that. Probably you want something like this instead:

OBJS    = $(SRCS:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)

Next this rule:

%.o : %.c
        $(CC) -o $(OBJS) -c $(SRC)

First the recipe is wrong. What does this expand to?

g++ -o ./build/foo.o ./build/bar.o -c ./src/foo.cpp ./src/bar.cpp

Clearly that's a totally invalid compile line. You want just the one object file and source file not all of them. This is what automatic variables are for:

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

However this is still wrong: this pattern rule will never match. Why? Because when make tries to build ./build/foo.o the % pattern matches the string ./build/foo. So when make looks to see if the prerequisite %.c exists it will check for ./build/foo.c. First, your filenames end in .cpp not .c so this should be %.cpp. But beyond that, the source files are in a different directory than the destination files so you can't just use %. You have to write it like this:

$(BUILD_DIR)/%.o : $(SRC_DIR)/%.cpp
        $(CC) -o $@ -c $<

I'll also point out that convention uses CC for the C compiler; if you're compiling C++ you should be using the CXX variable. Also you set a FLAGS variable but your compile rule doesn't actually use it; you can't just put it in the link rule. And, for C++ compiler flags the convention is to use CXXFLAGS as the variable.

Upvotes: 2

Related Questions