Mar 31

A Breif Tour of SConstruct

Category: Programming, Python

Tired of automake’s cryptic features and yet more cryptic errors? Feeling that ant doesn’t cut it for your non-java needs? Sick of trying to extend jam, cmake, and other build-specific languages? Try taking a look at SConstruct (www.scons.org) the extensible build environment written in the Python scripting language.

SConstruct is a build environment similar in capability to the GNU automake tools that is written on top of the python scripting language (http://www.python.org). Similar to other build tools it provides high-level target types such as “Program” and “Library” rather than forcing you to define every build step from cpp file to .lib, but SConstruct really shines in the following areas:

  1. The entire Python programming language is available right in the build file, making extension of the build system both easy and portable.
  2. SConstruct provides autoconf-like functionality allowing platform-specific configuration builds.
  3. Because the build file does not generate any intermediate artifacts (like a make file) errors pertain to the build file you wrote.

Your First SConstruct File

Building a Program is dead easy:


env = Environment(CPPPATH="inc/", LIBPATH="lib/")
env.Program("test", ["main.cpp", "common.cpp", "something_else.cpp"])

The first line creates and Environment object. This object keeps track of all the various settings used to build/link/etc a program such as include directories, libraries, and so on.

The second line defines the “test” program target as build built from a list of cpp files. That’s it!

SConstruct automatically detects the current build platform, selects a compiler, configures the build to create object files from cpp files and then an executable from the object files, and knows what extension to expect on that executable.

Adding a Custom Build Target

It is fairly common to want to add a custom target type. Let’s suppose you want to compile cheetah template files (http://www.cheetahtemplate.org/. This is a somewhat unusual task and not supported by built in target types.

In order to compile a .temp file into a .py file we need run run the following command:


cheetah compile --stdout --iext temp blah.temp > blah.py

The corresponding SConstruct would be the following:


cheetah_template_builder = Builder(action="cheetah compile --stdout --iext temp $SOURCE > $TARGET", suffix=".py", src_suffix=".temp")
env = Environment()
Environment["BUILDERS"]["CheetahTemplate"] = cheetah_template_builder
env.CheetahTemplate("blah")

Creating a More Complex Build Target

Some build targets require more than a simple command line execution. SConstruct also supports more complex target definitions including the ability to execute an arbitrary python function.


def SomeFunction(target, source, env):
    ...
builder = Builder(action=SomeFunction, ...)
...

Basic Platform Configuration

The final and most important aspect of SConstruct is its built in support for multi-platform configuration. Common operations such as checking for the existence of headers and libraries are supported out of the box and more complex operations are easy to add. The basic syntax for platform-specific configuration is as follows:


...
conf = Configure(env)
if not conf.CheckLibWithHeader("m", "math.h", "c"):
   con.env.Library("m", "math_sub/math.cpp")
if not conf.CheckLib("rt", "c"):
    print "Must have librt.lib to compile"
    sys.Exit(1)
...etc...
env = conf.Finish()

Adding a Custom Configuration Test

It is also possible to add custom tests in a similar manner to autoconf. For instance, checking for byte order:


bigendian_test_source_file= """
int main(int argc, char **argv){
        int i = 1;
        return ((char *)&i)[0] != 1;
}
"""

def CheckBigEndian(context):
        context.Message("Checking for big endianess ")
        result = context.TryRun(bigendian_test_source_file, '.c')
        context.Result(result[0])
        return result[0]

conf = Configure(env, custom_tests = {'CheckBigEndian' : common.CheckBigEndian})
if not conf.CheckBigEndian():
   ...etc...
env = conf.Finish()

Conclusions

SConstruct provides a relatively mature and flexible build environment that exceeds the capabilities of many tool such as jam and jet and meets the major feature set of established tools such as the GNU auto make system.

The Author

Michael Smit is a software engineer in Seattle, Washington who works for amazon

3 comments

Comments are closed.