Chapter 28. Troubleshooting

The experience of configuring any software build tool to build a large code base usually, at some point, involves trying to figure out why the tool is behaving a certain way, and how to get it to behave the way you want. SCons is no different. This appendix contains a number of different ways in which you can get some additional insight into SCons' behavior.

Note that we're always interested in trying to improve how you can troubleshoot configuration problems. If you run into a problem that has you scratching your head, and which there just doesn't seem to be a good way to debug, odds are pretty good that someone else will run into the same problem, too. If so, please let the SCons development team know using the contact information at https://scons.org/contact.html so that we can use your feedback to try to come up with a better way to help you, and others, get the necessary insight into SCons behavior to help identify and fix configuration issues.

28.1. Why is That Target Being Rebuilt? the --debug=explain Option

Let's look at a simple example of a misconfigured build that causes a target to be rebuilt every time SCons is run:

# Intentionally misspell the output file name in the
# command used to create the file:
Command('file.out', 'file.in', 'cp $SOURCE file.oout')
      

(Note to Windows users: The POSIX cp command copies the first file named on the command line to the second file. In our example, it copies the file.in file to the file.out file.)

Now if we run SCons multiple times on this example, we see that it re-runs the cp command every time:

% scons -Q
cp file.in file.oout
% scons -Q
cp file.in file.oout
% scons -Q
cp file.in file.oout

In this example, the underlying cause is obvious: we've intentionally misspelled the output file name in the cp command, so the command doesn't actually build the file.out file that we've told SCons to expect. But if the problem weren't obvious, it would be helpful to specify the --debug=explain option on the command line to have SCons tell us very specifically why it's decided to rebuild the target:

% scons -Q --debug=explain
scons: building `file.out' because it doesn't exist
cp file.in file.oout

If this had been a more complicated example involving a lot of build output, having SCons tell us that it's trying to rebuild the target file because it doesn't exist would be an important clue that something was wrong with the command that we invoked to build it.

Note that you can also use --warn=target-not-built which checks whether or not expected targets exist after a build rule is executed.

% scons -Q --warn=target-not-built
cp file.in file.oout

scons: warning: Cannot find target file.out after building
File "/Users/bdbaddog/devel/scons/git/mwichmann/scripts/scons.py", line 97, in <module>

The --debug=explain option also comes in handy to help figure out what input file changed. Given a simple configuration that builds a program from three source files, changing one of the source files and rebuilding with the --debug=explain option shows very specifically why SCons rebuilds the files that it does:

% scons -Q
cc -o file1.o -c file1.c
cc -o file2.o -c file2.c
cc -o file3.o -c file3.c
cc -o prog file1.o file2.o file3.o
%     [CHANGE THE CONTENTS OF file2.c]
% scons -Q --debug=explain
scons: rebuilding `file2.o' because `file2.c' changed
cc -o file2.o -c file2.c
scons: rebuilding `prog' because `file2.o' changed
cc -o prog file1.o file2.o file3.o

This becomes even more helpful in identifying when a file is rebuilt due to a change in an implicit dependency, such as an incuded .h file. If the file1.c and file3.c files in our example both included a hello.h file, then changing that included file and re-running SCons with the --debug=explain option will pinpoint that it's the change to the included file that starts the chain of rebuilds:

% scons -Q
cc -o file1.o -c -I. file1.c
cc -o file2.o -c -I. file2.c
cc -o file3.o -c -I. file3.c
cc -o prog file1.o file2.o file3.o
%     [CHANGE THE CONTENTS OF hello.h]
% scons -Q --debug=explain
scons: rebuilding `file1.o' because `hello.h' changed
cc -o file1.o -c -I. file1.c
scons: rebuilding `file3.o' because `hello.h' changed
cc -o file3.o -c -I. file3.c
scons: rebuilding `prog' because:
           `file1.o' changed
           `file3.o' changed
cc -o prog file1.o file2.o file3.o

(Note that the --debug=explain option will only tell you why SCons decided to rebuild necessary targets. It does not tell you what files it examined when deciding not to rebuild a target file, which is often a more valuable question to answer.)