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 "Controller B" build everything would have to be rebuilt, because SCons recognizes that the build instructions are different from those used in the "Controller A" build for each target - the build instructions are part of SCons's out-of-date calculation. 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 locations of the output files, 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 establishing one or more variant directory trees that are used to perform the build in, and thus provide a unique home for object files, libraries, and executable programs, etc. for a specific flavor, or variant, of build. SCons tracks targets by their path, so when the variant directory is included, objects belonging to "Controller A" can have different build instructions than those belonging to "Controller B" without triggering ping-ponging rebuilds.

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.