So far, our makefile for compiling our program of two modules looks like this:
# Link command: my_program: processing.o gui.o c++ processing.o gui.o -o my_program # Compilation commands: processing.o: processing.cxx c++ -c processing.cxx -o processing.o gui.o: gui.cxx c++ -c gui.cxx -o gui.o
This works wonderfully, but suppose now we want to change some compilation options. Or maybe we want to use a different compiler. We'd have to change all three compilation lines.
Similarly, suppose we want to change the list of modules to compile. We'd have to change it in two places, and if we accidently made the change in only one of them, it could be very difficult to track down the problem.
A better way to do it is to use variables, like this:
# Define the symbols we might want to change: CXX := c++ CXXFLAGS := -g OBJECTS := processing.o gui.o my_program: $(OBJECTS) $(CXX) $(OBJECTS) -o my_program processing.o: processing.cxx $(CXX) $(INCLUDES) $(CXXFLAGS) -c processing.cxx -o processing.o gui.o: gui.cxx $(CXX) $(CXXFLAGS) -c gui.cxx -o gui.o
$(CXX) expands to be the value of the variable
CXX, and similarly for
$(OBJECTS). Now we can just change one line in the
makefile, and all relevant compilation commands are affected.
In fact, we don't even need to change the makefile to change compilation options. Assignments specified on the command line override assignments in the makefile. For example, we could type this to the shell:
makepp CXXFLAGS="-g -O2"
which overrides the setting of
CXXFLAGS in the
makefile. It is as if the makefile contained the line
CXXFLAGS := -g -O2
instead of the definition it does contain.
It might not at all be useful to be able to override these things for your own development, but if you distribute your sources to other people, they might appreciate it.
Variable names are case sensitive (e.g.,
objects). Usually people write
most variables in upper case only, but you don't have to.
If you need to put a literal dollar sign into a rule action, write it with a double dollar sign, like this:
test: for testfile in *.test; do run_test $$testfile; done
Conventionally, there are a few variables which you might want to set. These are just conventions, but you will see them in a lot of makefiles.
CC := cc # The C compiler. CFLAGS := -g # C compilation options which relate to # optimization or debugging (usually # just -g or -O). Usually this wouldn't # include -I options to specify the # include directories, because then you # couldn't override it on the command line # easily. CXX := c++ # The C++ compiler. (Sometimes "CPP" instead # of CXX.) CXXFLAGS := -g # C++ compilation options related to # optimization or debugging (-O or -g). F77 := f77 # The fortran compiler. FFLAGS := # Optimization flags for fortran.
Makepp will guess appropriate values for some of these variables if you don't specify them, but it is usually best to set them explicitly--it makes it easier on anyone reading your makefile.
There are a lot more extremely powerful things you can do with variables, but first we need to explain some more things about makefiles.