Using make
Executive Summary:
This document is a brief description of the Unix make facility for
building executables. It gives some simple examples of Makefiles for
compiling C++ projects.
What is make?
Suppose I have a project consisting of two classes String and Stack,
The class String uses the Stack class to implement the Reverse()
operation. I've specified the interface for these classes and their
implementation in the files String.h, Stack.h, and String.C, Stack.C,
respectively. In addition, I have a main.C that uses the String class.
My project dependencies are then:
- Stack.C includes Stack.h
- String.C includes String.h and Stack,h
- main.C includes String.h
Ultimately, I'm building an executable revHW. What I would like is an
automatic way to compile the .C files into object files (.o), and then have
these linked to create revHW. However, I don't want to always type in the
g++ command lines every time I need to compile mu program. I could write
a shell script to do this for me, however I don't want to have to compile
evereything when just one module changes. For example, if I change Stack.C,
I need only recompile Stack.o and relink revHW, but none of the other .o's
need recompilation. If Stack.h changes, I need only recompile Stack.o
and String.o and relink revHW.
The above task can be accomplished with make. In the same directory
as my source create a file called "Makefile" with the contents (where
"<TAB>" is a single TAB indentation; This is essential --
using spaces won't work):
main.o:main.C String.h
<TAB>g++ -g -c -o main.o main.C
String.o: String.C String.h Stack.h
<TAB>g++ -g -c -o String.o String.C
Stack.o: Stack.C Stack.h
<TAB>g++ -g -c -o Stack.o Stack.C
revHW: main.o String.o Stack.o
<TAB>g++ -o revHW main.o String.o Stack.o
All you need to do to build revHW when you make a change to the source is
type:
% make revHW
and make will do the right thing.
More complicated files
The above Makefile is very simple, but for larger projects generating
such a Makefile like the above would be cumbersome. make has some
features to save some of your typing. In addition, programmers have
devised conventions for writing Makeiles that make it easy for one
to copy a previously used Makefile and easily modify it for any new
projects. This is illustrated in the Makefile below which accomplishes
the same as the above, but is written for more general purpose use:
# some variables describing your program source
# in most cases, you'll only need to edit these four variables
PROGRAM = revHW
HEADERS = String.h Stack.h
SOURCES = String.C Stack.C main.C
OBJECTS = main.o String.o Stack.o
# some useful others that you may need to edit
CC = g++
CFLAGS = -g
LIBS =
# name of this file
MF = makefile
.SUFFIXES: .o .h .C
# ------------- Stuff you shouldn't have to change ------------------
.C.o:
$(CC) $(CFLAGS) -c -o $*.o $<
$(PROGRAM): $(OBJECTS)
$(CC) -o $(PROGRAM) $(CFLAGS) $(OBJECTS) $(LIBS)
clean:
@rm -f *~ "#*" *.o $(PROJECT)
depend:
@echo 'updating the dependencies for:'
@echo ' ' $(SOURCES)
@{ \
< $(MF) sed -n '1,/^###.*SUDDEN DEATH/p'; \
echo '#' ; \
echo '# dependencies generated on: ' `date` ; \
echo '#' ; \
for i in $(SOURCES); do \
$(CC) -MM $(CFLAGS) $(DEFINES) $$i ; \
echo; \
done \
} > $(MF).new
@mv $(MF) $(MF).last
@mv $(MF).new $(MF)
##################### EVERYTHING BELOW THIS LINE IS SUBJECT TO SUDDEN DEATH...
#
# dependencies generated on: Wed Apr 2 23:23:09 PST 1997
#
String.o: String.C String.h Stack.h
Stack.o: Stack.C Stack.h
main.o: main.C String.h
As before, you build revHW with "make revHW". In addition, "make clean"
will remove the object files, executable, and auto-save files so you,
so you can start with a fresh project directory.
Automatically generating dependencies
In the example above, notice the "depend:" directive. The mess of
commands below it actually edits your Makefile to add the file dependencies
of your project at the bottom of the file. The last few lines of the
file were actually generated automatically by the command:
% make depend
You should do this anytime you add new source, or add/remove include
dependencies in your source code.