The make program is a Unix facility for describing dependencies among a group of related files, usually ones that are part of the same project. This facility has enjoyed widespread use in software-development projects. Programmers use make to describe how to "make" a program -- which source files need to be compiled, which libraries must be included, and which object files need to be linked. By keeping track of these relationships in a single place, individual members of a software-development team can make changes to a single module, run make, and be assured that the program reflects the latest changes made by others on the team.
Only by a leap of the imagination do we group make with the other commands for keeping track of differences between files. However, although it does not compare two versions of the same source file, it can be used to compare versions of a source file and to the formatted output.
Part of what makes Unix a productive environment for text processing is discovering other uses for standard programs. The make utility has many possible applications for a documentation project. One such use is to maintain up-to-date copies of formatted files -- which make up a single manual and provide users with a way of obtaining a printed copy of the entire manual without having to know which preprocessors or formatting options (Section 45.13) need to be used.
The basic operation that make performs is to compare two sets of files -- for example, formatted and unformatted files -- and determine if any members of one set, the unformatted files, are more recent than their counterpart in the other set, the formatted files. This is accomplished by simply comparing the last-modification date (Section 8.2) ("timestamp") of pairs of files. If the unformatted source file has been modified since the formatted file was made, make executes the specified command to "remake" the formatted file.
To use make, you have to write a description file, usually named Makefile (or makefile), that resides in the working directory for the project. The Makefile specifies a hierarchy of dependencies among individual files, called components. At the top of this hierarchy is a target. For our example, you can think of the target as a printed copy of a book; the components are formatted files generated by processing an unformatted file with nroff (Section 45.12).
Here's the Makefile that reflects these dependencies:
lp Section 45.2
manual: ch01.fmt ch02.fmt ch03.fmt lp ch0[1-3].fmt ch01.fmt: ch01 nroff -mm ch01 > ch01.fmt ch02.fmt: ch02 tbl ch02 | nroff -mm > ch02.fmt ch03.fmt: ch03a ch03b ch03c nroff -mm ch03[abc] > ch03.fmt
This hierarchy is represented in Figure 10-1.
The target is manual, which is made up of three formatted files whose names appear after the colon. Each of these components has its own dependency line. For instance, ch01.fmt is dependent upon a coded file named ch01. Underneath the dependency line is the command that generates ch01.fmt. Each command line must begin with a TAB.
When you enter the command make, the end result is that the three formatted files are spooled to the printer. However, a sequence of operations is performed before this final action. The dependency line for each component is evaluated, determining if the coded file has been modified since the last time the formatted file was made. The formatting command will be executed only if the coded file is more recent. After all the components are made, the lp (Section 45.2) command is executed.
As an example of this process, we'll assume that all the formatted files are up-to-date. Then by editing the source file ch03a, we change the modification time. When you execute the make command, any output files dependent on ch03a are reformatted:
$ make nroff -mm ch03[abc] > ch03.fmt lp ch0[1-3].fmt
Only ch03.fmt needs to be remade. As soon as that formatting command finishes, the command underneath the target manual is executed, spooling the files to the printer.
Although this example has actually made only limited use of make's facilities, we hope it suggests more ways to use make in a documention project. You can keep your Makefiles just this simple, or you can go on to learn additional notation, such as internal macros and suffixes, in an effort to generalize the description file for increased usefulness.
--TOR, from Unix Text Processing (Hayden Books, 1987)
Copyright © 2003 O'Reilly & Associates. All rights reserved.