Make is a facility for automated maintenance of programs. Make uses a file called a makefile which specifies the dependencies between component files, and the commands that will bring all component files up to date. Suppose you have a program that is in 3 different files and you modify one of these files. If one of the other unmodified files depends on something in the modified file, then the unmodified file should be recompiled as well as the one that was modified. When there are many source files, and the dependencies between them are complex, it would be very helpful if there were a way to specify these dependencies automatically. This is the role of the make facility. Make also serves to document how the components fit together.
The makefile provides the following information:
make argumentwhere argument is one of the targets given to the left of a ':' in a dependency rule (see below). If no argument is specified make will start with the first dependency rule in the makefile. To tell make that the makefile has a name other than the default , use the -f flag to pass the name of the makefile. If the makefile were called dactmake, the command:
make -f dactmake dactwill run make with the desired makefile, starting with the dependency rule that begins with dact.
target : components list TAB command1 TAB command2where TAB means the tab character, not the word TAB; it must come first on a command line. The target is the name of the file to be created; the components list is a list of files that are used to create the target file. This line is called a dependence rule. If make determines that the target needs to be updated, the commands following the dependence rule' will be executed. Make terminates if any of the commands is unsuccessful. An example is:
dact: main.o init.o process.o process2.o gcc -ansi -o dact main.o init.o process.o process2.oThe first line tells make that dact needs to be remade if any of the files to the right of the ':' are changed. Before checking the time the files were last changed, make will look for any dependence rule lines that start with each of components (main.o, init.o, process.o, and process2.o). If it finds any such lines, it will check if those components are up to date. Make determines which files have been changed by examining the time of last modification for each of the files. After checking that all the component files are up to date, and remaking any that were not, make brings dact up to date. If any of the files to the right of the ':' (main.o, init.o, process.o, or process2.o) were modified after the file to the left of the ':' (dact), then that file needs to be remade.
The second line tells make how it should remake the target dact, instructing it to link together the four object files.
If the component list has 0 elements then the commands given on the following lines will be executed only if you type
make targetMake will execute only those commands and then exit; for example, see the target clean in the example section below.
# makefile for dact # the sharp sign means the rest or the line is a comment dact: main.o init.o process.o process2.o gcc -ansi main.o init.o process.o process2.o -o dact # the next line says main.o depends on main.c # the line after it says to create main.o with the command # gcc -ansi -c main.c main.o: main.c gcc -ansi -c main.c # process.o depends on both process.c and process.h # and is created with the command gcc -ansi -c process.c process.o: process.c process.h gcc -ansi -c process.c process2.o: process2.c gcc -ansi -c process2.c # clean is a target with no components; when you make it, the # files main.o, init.o, process.o, and process2.o are removed clean: rm main.o init.o process.o process2.oRemember that make will only continue if no errors are reported by the commands it executes. If nothing needs to be updated or remade, make will report that the target is up to date:
make dact dact is up to dateThe above example does not fully exploit the capabilities of the make facility. Three of the four types of statements in a description file have been discussed above. The fourth and final type of statement is a macro definition. This statement has the form:
NAME = valueThe value of a macro is accessed by ${NAME}. Note that "macro definitions" are strikingly similar to shell script variables; macros are simply parameters used in the makefile. Lines 3-6 in the example above could be replaced with:
OBJS = main.o init.o process.o process2.o dact : $(OBJS) gcc -ansi $(OBJS) -o mainand the last line of the makefile could be replaced with
rm $(OBJS)
touch filenameand the modification date of the file filename will be changed. In the above example, even if no files had actually been modified, the command
touch process.hwould cause process.o to be remade, which would in turn require dact to be remade.
Department of Computer Science
University of California at Davis
Davis, CA 95616-8562