19.7. Where To Put Your Custom Builders and Tools

The site_scons directory gives you a place to put Python modules you can import into your SConscripts (site_scons), add-on tools that can integrate into SCons (site_scons/site_tools), and a site_scons/site_init.py file that gets read before any SConstruct or SConscript, allowing you to change SCons's default behavior.

If you get a tool from somewhere (the SCons wiki or a third party, for instance) and you'd like to use it in your project, the site_scons dir is the simplest place to put it. Tools come in two flavors; either a Python function that operates on an Environment or a Python file containing two functions, exists() and generate().

A single-function Tool can just be included in your site_scons/site_init.py file where it will be parsed and made available for use. For instance, you could have a site_scons/site_init.py file like this:


      def TOOL_ADD_HEADER(env):
         """A Tool to add a header from $HEADER to the source file"""
         add_header = Builder(action=['echo "$HEADER" > $TARGET',
                                      'cat $SOURCE >> $TARGET'])
         env.Append(BUILDERS = {'AddHeader' : add_header})
         env['HEADER'] = '' # set default value
  

and a SConstruct like this:


      # Use TOOL_ADD_HEADER from site_scons/site_init.py
      env=Environment(tools=['default', TOOL_ADD_HEADER], HEADER="=====")
      env.AddHeader('tgt', 'src')
  

The TOOL_ADD_HEADER tool method will be called to add the AddHeader tool to the environment.

Similarly, a more full-fledged tool with exists() and generate() methods can be installed in site_scons/site_tools/toolname.py. Since site_scons/site_tools is automatically added to the head of the tool search path, any tool found there will be available to all environments. Furthermore, a tool found there will override a built-in tool of the same name, so if you need to change the behavior of a built-in tool, site_scons gives you the hook you need.

Many people have a library of utility Python functions they'd like to include in SConscripts; just put that module in site_scons/my_utils.py or any valid Python module name of your choice. For instance you can do something like this in site_scons/my_utils.py to add build_id and MakeWorkDir functions:


      from SCons.Script import *   # for Execute and Mkdir
      def build_id():
         """Return a build ID (stub version)"""
         return "100"
      def MakeWorkDir(workdir):
         """Create the specified dir immediately"""
         Execute(Mkdir(workdir))
  

And then in your SConscript or any sub-SConscript anywhere in your build, you can import my_utils and use it:


      import my_utils
      print "build_id=" + my_utils.build_id()
      my_utils.MakeWorkDir('/tmp/work')
  

Note that although you can put this library in site_scons/site_init.py, it is no better there than site_scons/my_utils.py since you still have to import that module into your SConscript. Also note that in order to refer to objects in the SCons namespace such as Environment or Mkdir or Execute in any file other than a SConstruct or SConscript you always need to do


      from SCons.Script import *
  

This is true in modules in site_scons such as site_scons/site_init.py as well.

If you have a machine-wide site dir you'd like to use instead of ./site_scons, use the --site-dir option to point to your dir. site_init.py and site_tools will be located under that dir. To avoid using a site_scons dir at all, even if it exists, use the --no-site-dir option.