Reputation: 32354
I have a makefile which, when I need to add another file that is a part of the project, I also need to edit heavily to make it all work. I would like to just code my makefile once and be done with it! So, this is the script:
CC=g++
CFLAGS=-c -Wall
#All paths start in the main directory which has this makefile, object/ and code/.
OBJPATH=object#All compiled .o files need to be placed here.
CODEPATH=code#All .cpp and .hpp header files reside here.
#The names of all the object files that need to be made.
OBJ=$(OBJPATH)/World.o $(OBJPATH)/Block.o $(OBJPATH)/Creep.o $(OBJPATH)/Food.o $(OBJPATH)/Brick.o
all : World.a
$(OBJPATH)/World.o : $(CODEPATH)/World.hpp $(CODEPATH)/World.cpp
$(CC) $(CFLAGS) $(CODEPATH)/World.cpp
mv World.o $(OBJPATH)/
$(OBJPATH)/Block.o : $(CODEPATH)/Block.hpp $(CODEPATH)/Block.cpp
$(CC) $(CFLAGS) $(CODEPATH)/Block.cpp
mv Block.o $(OBJPATH)/
$(OBJPATH)/Creep.o : $(CODEPATH)/Creep.hpp $(CODEPATH)/Creep.cpp
$(CC) $(CFLAGS) $(CODEPATH)/Creep.cpp
mv Creep.o $(OBJPATH)/
$(OBJPATH)/Food.o : $(CODEPATH)/Food.hpp $(CODEPATH)/Food.cpp
$(CC) $(CFLAGS) $(CODEPATH)/Food.cpp
mv Food.o $(OBJPATH)/
$(OBJPATH)/Brick.o : $(CODEPATH)/Brick.hpp $(CODEPATH)/Brick.cpp
$(CC) $(CFLAGS) $(CODEPATH)/Brick.cpp
mv Brick.o $(OBJPATH)/
#This archive is the final result of the compilation:
World.a : $(OBJ)
ar rvs World.a $(OBJ)
cp $(CODEPATH)/World.hpp . #I need both the World.a file and the World.hpp file from code/ for this library to function.
#Delete all object files and the archive:
clean :
rm $(OBJPATH)/*.o World.a World.hpp *~ $(CODEPATH)/*~
#Delete all backup files made by Gedit:
pretty :
rm *~ $(CODEPATH)/*~
What this basically does is compiles all the .o
files in the folder object/
, and then puts them in a file named World.a
. Then it just copies over World.hpp
, because that's the library's header file. I believe that a lot of this code can be minimized so it's more readable and generic (doesn't require me to edit it each time I make a new class).
Upvotes: 1
Views: 241
Reputation: 99094
Look at the rule for one object file:
$(OBJPATH)/World.o : $(CODEPATH)/World.hpp $(CODEPATH)/World.cpp
$(CC) $(CFLAGS) $(CODEPATH)/World.cpp
mv World.o $(OBJPATH)/
Let's build the object where we want it, instead of using mv
:
$(OBJPATH)/World.o : $(CODEPATH)/World.hpp $(CODEPATH)/World.cpp
$(CC) $(CFLAGS) $(CODEPATH)/World.cpp -o $(OBJPATH)/World.o
then use an automatic variable:
$(OBJPATH)/World.o : $(CODEPATH)/World.hpp $(CODEPATH)/World.cpp
$(CC) $(CFLAGS) $(CODEPATH)/World.cpp -o $@
then reverse the order of the prerequisites, so that we can use another automatic variable:
$(OBJPATH)/World.o : $(CODEPATH)/World.cpp $(CODEPATH)/World.hpp
$(CC) $(CFLAGS) $< -o $@
Now the command doesn't mention World
by name, so we could use the same rule for all the objects. To make this answer short I'll first make it a static pattern rule:
$(OBJPATH)/World.o : $(OBJPATH)/%.o : $(CODEPATH)/%.cpp $(CODEPATH)/%.hpp
$(CC) $(CFLAGS) $< -o $@
then combine them all:
OBJ=$(OBJPATH)/World.o $(OBJPATH)/Block.o $(OBJPATH)/Creep.o $(OBJPATH)/Food.o $(OBJPATH)/Brick.o
$(OBJ) : $(OBJPATH)/%.o : $(CODEPATH)/%.cpp $(CODEPATH)/%.hpp
$(CC) $(CFLAGS) $< -o $@
Now when you want to add a new file, all you have to do is add it to the OBJ=...
line. There are a few more improvements you can make, but this is enough for one day.
Upvotes: 2