corazza
corazza

Reputation: 32354

How to make my makefile more general?

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

Answers (1)

Beta
Beta

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

Related Questions