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.
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.
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.
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.