Thursday, April 02, 2009

Avoid hard coded variant directories by using a SCons Repository

One of the things about SCons that I didn't like was that by default it built your object files in the same directory as your source code. This means you end up with this:
Your ${VCS} status output would be full of this sort of thing:
Untracked files:
? src/foo.o
Tab completion would stop at vi src/foo., grep would add spurious "Binary file foo.o matches". Yuck, what a mess.

Then you discover VariantDir in the SCons documentation and this looks great. You add variant_dir="build", quickly followed by duplicate=False, and all is well. However, this hard coding of "build" is a bit lame. Think about autotools - you could build out-of-source to any directory you liked...
mkdir /tmp/build
cd /tmp/build
/path/to/source/configure && make
Wouldn't it be great if SCons could do this?

It can!

This is a little known feature that I recently stumbled upon completely by chance. Assuming the code is in ~/projects/code, the magic incantation is as follows:
scons -Y ~/projects/code -f ~/projects/code/SConstruct
This uses a SCons secret weapon - Repositories. As a bonus, this particular feature is not even mentioned in the documentation. It means you can compile into any directory using the original source code. The explanation is that the options do the following:
-Y REPOSITORY Search REPOSITORY for source and target files.
-f FILE Read FILE as the top-level SConstruct file.
By saying use this SConstruct to build the code and if you don't find a file, look here, you emulate the autotools/CMake out-of-source behaviour almost perfectly. If the command line looks long, just add --interactive. That way hitting "b" and enter will rebuild.

Hang on, because there are 2 caveats.

First, you have to be careful that when you specify files that are not handled natively by SCons that you use the right names, i.e. in your own Builders. Also internal include directories should use # so that they mean "from the top of the source tree" rather than from the top of the build tree. That means env.Append(CPPPATH=['#mylib']) instead of just "mylib".

Secondly, and more annoyingly, the build directory can't be below the source directory. SCons gets all confused and starts putting another build directory in your build directory (so you can build while you build). But then crashes out saying it can't find the source code. Boo!

Apart from that, you're good to go.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.