The Program Organizer make

When writing large programs, compiling can be quite time consuming. Suppose you have to make a change to one line in one function in your code. Despite the fact that you made a small change, you must wait to recompile the entire program. Would it not be nice to be able to break the program up into several pieces and recompile just those that you have changed? It would be even more convenient if there were an automated way to have the pieces that you changed recompiled and the pieces that had not changed left alone.

make is a facility for automated maintenance of programs. make uses a file called a “makefile” that 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:

Note that if file B depends on file A and file A is changed, then file B must be recompiled even though it was not changed. This is the type of dependency that is specified in the makefile.

The makefile must be in the current working directory. make assumes that the makefile is named makefile or Makefile unless told otherwise. To run make, type:

make argument
where 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. For example, if the makefile were called dactmake, the command:
make -f dactmake dact
will run make with the desired makefile, starting with the dependency rule that begins with “dact”.


A typical entry for a makefile is of the form

target : components list
TAB    command1
TAB    command2
where TAB means horizontal the tab character (control-I), 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 -pedantic -Wall -o dact main.o init.o process.o process2.o

The 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, and 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 (as usual, what you type is in bold Courier typeface and what the computer types is in Roman Courier typeface)

% make target
make will execute only those commands and then exit; for example, see the target “clean” in the example section below.


A complete example description file follows. The character “#” introduces a comment that runs to the end of the line.

# 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 -pedantic -Wall 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 -pedantic -Wall -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 -pedantic -Wall -c process.c

process2.o: process2.c
    gcc -ansi -pedantic -Wall -c process.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
    rm main.o init.o process.o process2.o

Remember 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 date

The 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 = value
The value of a macro is accessed by either $(NAME) or ${NAME}. Macros are simply parameters used in the makefile. Lines 3–4 in the example above could be replaced with:
OBJS = mail.o init.o process.o process2.o
dact : $(OBJS)
    gcc -ansi $(OBJS) -o main.o
and the last line of the makefile could be replaced with
rm $(OBJS)


The command touch(1) updates the modification date of a file to the current time and can be used to force the remaking of a target. Just type

% touch filename
and 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.h
would cause process.o to be remade, which would in turn require dact to be remade.


This document was originally written by Kendrick Mock and modified by Matt Bishop.

You can also obtain a PDF version of this. Version of September 30, 2015 at 12:10AM