21
votes

I am trying to write a Makefile with my source and object files separated and I can't seem to figure out the proper way to accomplish this. I have two methods that work but I'm hoping someone can point the "correct" way to do this is.

My project is separated into a src and obj folder with the Makefile at the same level as these.

The first method uses the wildcard function to find the source files in src then uses text replacement to determine the corresponding object files.

SRC = $(wildcard src/*.cpp)
OBJ = $(SRC:.cpp=.o)

prog: $(OBJ)
       $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) -o prog $(patsubst src/,obj/,$(OBJ))

%.o: %.cpp
     $(CC) $(CFLAGS) -c $< -o $(COMPILE)/$(@F)  

This seems to work, however, every time I run make prog it recompiles all the object files. The OBJ variable has to have the src/ in front of all the objects or else I get the "no rule to make target". On the plus side, I can easily use the patsubst in the prog target to specify the object files.

The second method is similar but uses vpaths and text replacement on the OBJ variable:

 vpath = %.cpp src
 vpath = %.o obj

 SRC = $(wildcard src/*.cpp)
 OBJ = $(subst src/,,$(SRC:.cpp=.o))
 POBJ = $(patsubst src/,obj/$(SRC:.cpp=.o))

 prog: $(OBJ)
       $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) -o prog $(POBJ)

 %.o: %.cpp
     $(CC) $(CFLAGS) -c $< -o $(COMPILE)/$(@F)  

This eliminates the recompiling of object files, but requires me to add another variable POJB for the prog target (since I can't do any patsubst on just the object files without a basedir).

Both methods work and each has its advantages over the other but which one is the "correct" approach and if neither, what is the proper way to achieve this type of building?

1

1 Answers

25
votes

Your first example is almost there:

SRC = $(wildcard src/*.cpp)
OBJ = $(patsubst src/%.cpp, obj/%.o, $(SRC))

prog: $(OBJ)
  $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) $(OBJ) -o prog 

obj/%.o: src/%.cpp
  $(CC) $(CFLAGS) -c $< -o $@