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?
If you want to do wildcard expansion in such places, you need to use the wildcard function, like this: $(wildcard pattern ...) This string, used anywhere in a makefile, is replaced by a space-separated list of names of existing files that match one of the given file name patterns.
A rule appears in the makefile and says when and how to remake certain files, called the rule's targets (most often only one per rule). It lists the other files that are the prerequisites of the target, and the recipe to use to create or update the target.
$$ means be interpreted as a $ by the shell. the $(UNZIP_PATH) gets expanded by make before being interpreted by the shell.
The variable $@ represents the name of the target and $< represents the first prerequisite required to create the output file.
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 $@
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With