makecommand is a *NIX tool that allows you manage the compilation of one or more source files. For an application with just one source file,
makedoes not improve the compilation efficiency. However, for projects made up of multiple source files, recompiling all files every time a change is made can take a lot of time.
Consider a project where you have 3 source files,
source3.C; and 3 header
To compile such a program, you might type:
g++ -Wall source1.C source2.C source3.C -o projectTo get an executable program named
project. Now imagine that during testing, you found a bug in
source2.C. You edit that file, fix the bug, and are now ready to recompile your program. Using the command used earlier, all source files are recompiled, even though
source2.Cis the only one that was changed.
make is designed to identify files that have been changed,
and only recompile those files. As files are recompiled, other dependent
files may be recompiled. At the end of the process, the changed files
and any dependent files have been recompiled, but other unchanged files
are not recompiled.
This tutorial is not intended to be an exhaustive document on what
make can do. It is intended to be an introduction to
the basic features
make provides. See the References
section for links to more detailed tutorials.
make, we need to break these steps apart.
2.1 Multi-Step CompilationTo make our compiler stop after the assembler has run, we can specify the
-cswitch.% g++ -Wall -c source1.C -o source1.o % g++ -Wall -c source2.C -o source2.o % g++ -Wall -c source3.C -o source3.oHere,
source1.Cwas compiled into an object file named
source2.C, which was then compiled into an object file named
source3.Cwas then compiled into an object file named
Note that none of these .o files are executable. A file step must be executed to executed to link all of these individual object files into a single executable.% g++ -Wall source1.o source2.o source3.o -o projectNow, we have
projectwhich is an executable program.
2.2 Taking Advantage of Multi-Step CompilationOkay, so we can turn one command for compiling a program into four. How does that help me? Well, here again we'll look at making a code change to one of the source files. Say we change something in
source2.C. What do we need to do to build our application?
source1.Cdoes not depend on
source2.Cand we already have
source1.oso we do not have to recompile
source1.C.% g++ -Wall -c source2.C -o source2.o % g++ -Wall -c source3.C -o source3.o % g++ -Wall source1.o source2.o source3.o -o projectNow, we have
projectwhich is an executable program and we did not recompile
As you can see, it is possible to use multi-step compilation manually to prevent unnecessary recompilations. However, as project grow larger and larger, we'd like a way to automate this process.
maketo the rescue!
makefileis a file that contains a set of rules governing commands to be executed. The basic form of these rules is:
<target>: <dependent files> <tab><commands to build target> ...Where target is the name associated with this specific build rule, dependent files is a list of files that this target depends on, and the list of commands to build the target are programs that will be executed to build the target. Notice that the tab character has to prefix each command line.
Let's consider our previous example. We want to make a makefile to build our project. Makefiles are usually named either "makefile" or "Makefile" Such a makefile might look like the following:
all: project project: source1.o source2.o source3.o g++ -Wall source1.o source2.o source3.o -o project source1.o: source1.C source1.h g++ -Wall -c source1.C -o source1.o source2.o: source2.C source2.h source1.o g++ -Wall -c source2.C -o source2.o source3.o: source3.C source3.h source1.o source2.o g++ -Wall -c source3.C -o source3.oNow, if our project has never been built before, if we type
make allon the command line, where
allis the target to be built, make will determine that the target all is dependent on the file project. The file project does not exist, so it needs to be built.
makethen looks for a rule named
project. It sees that the file
projectis dependent upon three other file,
source3.o. It looks for those file, sees that they are not there so it must build them. It repeats this process until all files are built.
In the future, if a modification is made to
make evaluates the dependency list, it will see that
project depends on
source2.o depends on
source2.C has been modified since
source2.o was built (make determines this by the timestamps
on the files), so it must be rebuilt. Then everything depending on that
must be rebuilt. Then everything depending on that must be rebuilt.
This continues until everything that needs to be rebuilt is rebuilt.
make process is not limited to compiling. For example
one frequent rule in makefiles is one to clean up all the generated
files. In our example, such a rule might look like:
clean: rm *.o projectHere, if we type
make clean, all the object files and the executable will be removed.
Let's again take a look at our example.
# # This is a comment. Comments should be used to document # your makefile just like one of your programs. # CC=g++ CC_OPTS=-Wall PROJECT=project RM=/bin/rm all: $(PROJECT) $(PROJECT): source1.o source2.o source3.o $(CC) $(CC_OPTS) source1.o source2.o source3.o -o $(PROJECT) source1.o: source1.C source1.h $(CC) $(CC_OPTS) -c source1.C -o source1.o source2.o: source2.C source2.h source1.o $(CC) $(CC_OPTS) -c source2.C -o source2.o source3.o: source3.C source3.h source1.o source2.o $(CC) $(CC_OPTS) -c source3.C -o source3.o clean: $(RM) *.o projectThis is basically the same make file as we saw before. This time, however, we're using variables. For example, the
CC_OPTSvariable hold options we're passing to the compiler. If we wanted to add an additional options, say
-g, we could add it in that one place, instead of five in the previous.