Chapter 15. Separating Source and Build Trees: Variant Directories

It's often useful to keep any built files completely separate from the source files. Consider if you have a project to build software for a variety of different controller hardware. The boards are able to share a lot of code, so it makes sense to keep them in the same source tree, but certain build options in the source code and header files differ. If you build "Controller A" first, then "Controller B", on the second build everything would have to be rebuilt, because SCons sees that the build instructions differ, and thus the targets that depend on those different instructions are not valid for the current build. Now when you go back and build for "Controller A", things have to be rebuilt from scratch again for the same reason. However, if you can separate the places the output files go, this problem can be avoided. You can even set up to do both builds in one invocation of SCons.

You can enable this separation by creating one or more variant directory trees that are used to hold the built objects files, libraries, and executable programs, etc. for a specific flavor, or variant, of build. SCons provides two ways to do this, one through the SConscript function that we've already seen, and the second through a more flexible VariantDir function.

Historical note: the VariantDir function used to be called BuildDir, a name which was removed because the SCons functionality differs from a familiar model of a "build directory" implemented by other build systems like GNU Autotools. You might still find references to the old name on the Internet in postings about SCons, but it no longer works.

15.1. Specifying a Variant Directory Tree as Part of an SConscript Call

The most straightforward way to establish a variant directory tree relies the fact that the usual way to set up a build hierarchy is to have an SConscript file in the source subdirectory. If you pass a variant_dir argument to the SConscript function call:

SConscript('src/SConscript', variant_dir='build')

SCons will then build all of the files in the build subdirectory:

% ls src
SConscript  hello.c
% scons -Q
cc -o build/hello.o -c build/hello.c
cc -o build/hello build/hello.o
% ls src
SConscript  hello.c
% ls build
SConscript  hello  hello.c  hello.o

No files were built in src, they went to build. The build output might show a bit of a surprise: the object file build/hello.o and the executable file build/hello were built in the build subdirectory, as expected. But even though our hello.c file lives in the src subdirectory, SCons has actually compiled a build/hello.c file to create the object file, and that file is now seen in build.

What's happened is that SCons has duplicated the hello.c file from the src subdirectory to the build subdirectory, and built the program from there (it also duplicated SConscript). The next section explains why SCons does this.