# Debugging Makefiles

## .makepp_log

If you have a complicated build procedure, you find that makepp is rebuilding things more often than you think they need to be rebuilt. Or (hopefully this is rarer) you may find that it is not rebuilding things when it should. You don't have to keep staring at your makefiles until you see the problem. On every build, makepp produces a log file that explains which rule it thought it was supposed to use to build each target, what files it thought each target depended on, and (if it did decide to rebuild) why it thought a rebuild was necessary. This file is called `.makepp_log` and it is placed in the directory you actually ran makepp from. (Of course, the filename has a leading period, which means that you won't see it there unless you specifically look for it. It's designed to be unobtrusive.)

The log file is more or less self-explanatory. The only thing that might be a little obscure is the leading number on each line; this means the fork level of makepp. This will always be 0 unless makepp is trying to rebuild a makefile, in which case it will be 1. If a makefile contains instructions for rebuilding itself, makepp forks, rebuilds the makefile if necessary, and then reads the makefile and builds the other targets.

Indentation conveys depth in makepp's inference tree. Suppose the target is `all`, and `all` depends on `my_program`, and `my_program` depends on `*.o`, which depend on the corresponding `.c` files. Log messages related to `all` will not be indented, log messages related to building the target `my_program` will be indented two spaces, log messages related to building any of the object files will be indented 4 spaces, and log messages related to building any of the source files will be indented 6 spaces.

If you're doing a parallel make (using the `-j` command line option), the order of the messages in the log file will not make nearly as much sense since messages from different targets will be interspersed. You might try debugging a serial make first.

## Common errors in makefiles

### Not specifying all dependencies

Makepp is designed to be extremely clever about finding dependencies, and if you just use a standard unix C or C++ compiler command, it is actually somewhat difficult to get makepp to miss something. (Please send me examples if you find that it missed something, so I can make makepp smarter.) However, if you are running commands other than compilation, or dealing with languages other than C or C++, it is much easier to run into problems.

If you don't tell makepp all of the dependencies of a file, and it can't infer them by looking at the command line or scanning the files for includes, then it may not rebuild a file when it should. You can make this kind of error less likely by using only automatic variables in your actions, rather than repeating the dependency lists. For example,

    my_program: a.o b.o c.o
    	ld a.o b.o c.o d.o -o my_program

has an error because `d.o` is mentioned in the action but not in the dependency list. If the command had been written this way:

    my_program: a.o b.o c.o
    	$(CC) $(inputs) -o my_program

then the lack of `d.o` would have been noticed because it would have caused link errors.

Another way that a missing dependency can occur is if a program actually uses a file but doesn't take the file's name on the command line. For example, if you're compiling Fortran code, makepp at the moment doesn't know how to scan for included files. Thus you must explicitly list any files that are included.

One thing that is sometimes helpful for testing is to start with a completely clean directory--just the bare minimum you think should be necessary--and rebuild absolute everything from scratch. This can be most conveniently done by using repositories, like this:

    rm -rf test-build-dir
    makepp -R test-build-dir=. -F test-build-dir

If the build fails because some file is not present, it means that makepp didn't realize some file was a dependency, because it only links files from the repository that it thought were needed. Performing this test occasionally may save hours of debugging later. I have worked on projects where this was never done for months because it took so long. As a result, many little problems crept in. There were some object files that didn't have source files any more, some source files that were never properly rebuilt by a preprocessing command, etc.

Of course, this won't catch all missing dependencies, but it will catch some of them.

### Not specifying all targets

You must specify all files that a given command modifies as targets, or else makepp may not have realized they have changed. You can specify more than one target. For example,

    y.tab.h y.tab.c: parse.y
    	yacc -d parse.y

If you had forgotten to specify `y.tab.h` as a target, then makepp would not know to rebuild `y.tab.h` using this command, and files that depend on `y.tab.h` might not be recompiled after the yacc command is run.

### Suggestions?

Please suggest things that you have found confusing or dangerous, and I'll either note them or try to fix makepp so they aren't a danger any more.

Tutorial index | Previous (source/objects and build variants)
Last modified: Tue Dec 26 21:13:02 PST 2000