# A simple makefile

Suppose you are writing a C++ program which has two source modules, `processing.cxx` and `gui.cxx`, along with numerous include files. If you were to build your program from scratch, you would need to execute something like these commands:

    c++ -c processing.cxx -o processing.o
    c++ -c gui.cxx -o gui.o
    c++ processing.o gui.o -o my_program

The first two commands are compilation commands, and the third invokes the linker to combine the two object files into a single executable. If you make changes to `gui.cxx` but not to `processing.cxx`, then you don't need to reexecute the first command, but you do need to execute the last two commands. makepp can figure this out for you automatically.

(If you've never worked with make before, you may be thinking that you could combine the above three commands into a single command, like this:

    c++ processing.cxx gui.cxx -o my_program

When you omit the `-c` option to the compiler, it combines the compilation and linking step. This is often quite convenient when you are not writing a makefile. However, it's not a good idea to do this in a makefile, because it always recompiles both modules even if one of them hasn't changed, and this can take a significant amount of extra time.)

In order to use makepp to control the build process, you'll need to write a makefile. The makefile is a text file that contains the recipe for building your program. It usually resides in the same directory as the sources, and it is usually called `Makefile`.

Each one of these commands should be a separate rule in a makefile. A rule is an instruction for building one or more output files from one or more input files. Makepp determines which rules need to be reexecuted by determining whether any of the input files for a rule have changed since the last time the rule was executed.

A rule has a syntax like this:

    output_filenames : input_filenames
    	actions

The first line of the rule contains a space-separated list of output files, followed by a colon, followed by a space-separated list of input files. The output files are also called targets, and the input files are also called dependencies; one says that the target file(s) depends on the dependencies, because if any of the dependencies change, the target must be rebuilt.

The remaining lines of the rule (the "actions") are shell commands to be executed. Each action must be indented with at least one space (traditional make requires a tab character). Usually, there's just one action line, but there can be as many as you want; each line is executed sequentially, and if any one of them fails, the remainder are not executed. The rule ends at the first line which is not indented.

You can place the rules in any order in the makefile, but it is traditional to write the rule that links the program first, followed by the compilation rules. One reason for this is that if you simply type "`makepp`", then makepp attempts to build the first target in the file, which means that it will build your whole program and not just a piece of it. (If you want to build something other than the first target, you have to specify the name of the target on the command line, e.g., "`makepp processing.o`".)

The above compilation commands should be written as three separate rules. A makefile for building this program could look like this:

    # Link command:
    my_program: processing.o gui.o
    	c++ processing.o gui.o -o my_program

    # Compilation commands:
    processing.o: processing.cxx
    	c++ -c processing.cxx -o processing.o

    gui.o: gui.cxx
    	c++ -c gui.cxx -o gui.o

(Characters on a line following a `#` are ignored; they are just comments. You do not need the "`# Link command:`" comment in the makefile at all.)

To use this makefile, simply cd to the directory and type "`makepp`". Makepp will attempt to build the first target in the makefile, which is `my_program`. (If you don't want it to build the first target, then you have to supply a the name of the target you actually want to build on the command line.)

When makepp attempts to build `my_program`, it realizes that it first must build `processing.o` and `gui.o` before it can execute the link command. So it looks at the other rules in the makefile to determine how to build these.

In order to build `processing.o`, makepp uses the second rule. Since `processing.o` depends on `processing.cxx`, makepp will also try to make `processing.cxx`. There is no rule to make `processing.cxx`; it must already exist.

Makepp checks whether `processing.cxx` has changed since the last time `processing.o` was built. By default, it determines this by looking at the dates on the file. Makepp remembers what the date of `processing.cxx` was the last time `processing.o` was made by storing it in a separate file (in a subdirectory called `.makepp`). Makepp will execute the actions to build the target if any of the following is true:

- The target does not exist.
- The target exists, but makepp does not have any information about the last build.
- The date on any input file has changed since the last build.
- The date on any target has changed since the last build.
- The actions have changed since the last build.
- The last build occured on a different architecture (different CPU type or operating system type).

It might seem a little funny that makepp executes the action if either the output file or the input files have changed since the last build. Makepp is designed to guarantee that your build is correct, according to the commands in the makefile. If you go and modify the file yourself, then makepp can't guarantee that the modified file is actually correct, so it insists on rebuilding. (For more information on how makepp decides whether to rebuild, and how you can control this, see the section in the reference manual on signature checking.)

Now `processing.o` might not depend only on `processing.cxx`; if `processing.cxx` includes any `.h` files, then it needs to be recompiled if any of those `.h` files has changed, even if `processing.cxx` itself has not changed. You could modify the rule like this:

    # Unnecessary listing of .h files
    processing.o: processing.cxx processing.h simple_vector.h list.h
    	c++ -c processing.cxx -o processing.o

However, it is a real nuisance to modify the makefile every time you change the list of files that are included, and it is also extremely error prone. You would not only have to list the files that `processing.cxx` includes, but also all the files that those files include, etc. You don't have to do this. Makepp is smart enough to check for include files automatically. Any time it sees a command that looks like a C or C++ compilation (by looking at the first word of the action), it reads in the source files looking for `#include` directives. It knows where to look for include files by scanning for `-I` options on your compiler command line. Any files which are included are automatically added to the dependency list, and any files which those include. If any of them has changed, the file will be recompiled.

Once makepp knows that `processing.o` is up to date, it then determines whether `gui.o` needs to be rebuilt by applying the same procedure to the third rule. When both `processing.o` and `gui.o` are known to be built correctly, then makepp applies the same procedure to see if the link command needs to be reexecuted.

The above makefile will work, but even for this simple problem, an experienced user is not likely to write his makefile this way. Several improvements are discussed in the next pages.

Tutorial index | Next (using variables) | Previous (unix compilation commands)
Last modified: Wed Dec 27 13:11:16 PST 2000