Computer Science
Research  Teaching  People  Community   

Contact Us
Undergrads • Grad Students • Faculty • Staff • Alumni • Locator • Phones

Makefiles Tutorial

Creating a large web site with a consistent style -- colors, fonts, layout, pictures, and so on -- is a daunting task. Making a small change to each file across the entire site is even worse. For this reason, the CS web team uses the make utility and the C preprocessor to create pages automatically from a single set of templates. Creating a new page takes considerably less time, and propagating a change across the site is almost trivial.

What is the make utility?

Make is a utility for handling dependencies within a project. A given product file depends on one or more source files, and if any of the source files changes, the product file must be rebuilt. The make command automates this.

A makefile is a listing of product files (targets) and the source files required to build them. Typically the product files are executables, and the source files are the source code required to build them. On our web site, the product files are .html files, and the source files are the templates (.raw files) used to build them. Thus with one make command, we turn a directory full of .raw files into .html files suitable for viewing in a browser.

What is the C preprocessor?

The C preprocessor is the component of a C compiler that includes #include files, expands #define macros, and parses out comments. The CS web team uses it as a macro language for turning .raw web templates into .html web pages.

An in-depth study of the C preprocessor would be out of place here. For more information, get a book about the C language.

Makefile syntax

Makefiles consist of variable assignments, target dependency rules, and build instructions.

Variable assignments take the form

and serve to isolate things that might change at the top of the file. Variable assignments are optional but are highly recommended because they simplify future changes to the makefile. They serve the same purpose that constant declarations (including #define statements) serve in a high-level language.

Variable values are accessed as ${VARIABLENAME} or $(VARIABLENAME).

Target dependency rules take the form

  target: source1 source2 source3
and denote from which source file(s) a given target is built. The first target specified in the makefile is the one built if you call make with no parameters. This is usually the all target.

The sources on which a target depends do not necessarily have to be actual files. They can be other targets. Thus one could make the target rule

  all: index.html foo.html bar.html
which would say that whenever make all (in most cases, make by itself will do the same) is run, index.html, foo.html, and bar.html should be built.

Target rules may also contain wildcards. This serves to specify how to create one entire class of files given sources from another class of files. For example, the rule

  %.html: %.raw ${INCFILES}
says that any file ending in .html depends on a similarly named file ending in .raw and everything included in the variable INCFILES.

Build rules specify how to build a target file. Each target rule is followed by zero or more build commands. Note: each build command in a build rule must start with a tab character, and there can be no blank lines inside a build rule.

The build rule for the target dependency rule specified above is

      @rm -f $@
      ${CPP} -I${INCDIR} -P $< > $@
First, some fun with syntax. Now, an overview. The first line silently removes any existing copy of the target file. The second line runs the C preprocessor on the source .raw file and saves the output into the target .html file.

How the web team uses make

The CS web team uses make to build three classes of targets: .html files, .shtml (server-parsed HTML) files, and subdirectories. The ability to build subdirectories means that typing make at the top of a web will build the current directory and all directories below.

The templates for .html files end in .raw. The templates for .shtml files end in .sraw. Each makefile should contain two wildcard-based rules:

  %.html: %.raw
  %.shtml: %.sraw
There are no template files or build rules for building subdirectories.

The new makefile system

The old CS web team makefile system used variables called HTMLFILES and RAWFILES to store lists of the targets that needed to be built in a directory and the .raw files used to build them. In many makefiles, there were also lists of subdirectories that needed to be built recursively. This led to broken makefiles far too often, because many web team members did not understand the mechanics of adding or removing a target or a subdirectory.

The new makefile system uses a shell script to find automatically all of the files and subdirectories that need to be built. The makefiles no longer have any static lists, and, for the most part, makefiles are interchangeable from directory to directory.

The shell script is called amake (for "automatic make") and is located in /home/webman/bin. It finds all .raw files and calls make to build the corresponding .html files. Then it finds all .sraw files and calls make to build the corresponding .shtml files. Then it finds all makefiles in all subdirectories and calls amake on them recursively. Under the webman account, make is simply an alias to amake.

Other information

Calling make (just an alias to amake) alone builds all targets in the current directory and in all subdirectories. Calling make with a target file as a parameter (e.g., make foo.html) builds only the one file specified.


  • - make(1) man page
  • - cpp(1) man page

    UVa CS Department of Computer Science
    School of Engineering, University of Virginia
    151 Engineer's Way, P.O. Box 400740
    Charlottesville, Virginia 22904-4740

    (434) 982-2200  Fax: (434) 982-2214
    Web Comments:
    Admissions Inquiries:
    Site directory, Other addresses
    Server statistics
    © Created by the CS Web Team