This page describes one way to create a modular build that can support multiple platforms and support building multiple setups at a time. This is one way, not necessarily the best way.
Supporting multiple builds
To support multiple builds at a time, each build can be separated into a setup file. One or more files can be specified by the SETUP on the command line. If none are specified only the command line options are used:
1 import os 2 import glob 3 4 setup = ARGUMENTS.get('SETUP', None) 5 if setup is None: 6 setup = [ None ] # If not setup specified, do one pass only with ARGUMENTS 7 else: 8 parts = setup.split(os.pathsep) 9 setup =  10 for part in parts: 11 setup.extend(glob.glob(part)) 12 if len(setup) == 0: 13 print 'SETUP specified but no matching setup files found' 14 Exit()
Separating the configuration
To simplify the configuration of the environments and reduce the amount of conditional tests, each supported platform,compiler,etc is separated into a configuration module. This configuration is specified by the CONFIG option and loaded dynamically. It contains certain useful functions for creating the options, environment, and configure tests, as well as preparing the environment with any needed variables and flags. Before creating this configuration, it still needs to be detected from the setup file or command line:
1 def DetectConfig(file, args): 2 import sys 3 4 dummyvars = Variables(file, args) 5 dummyvars.Add('CONFIG') 6 dummyenv = Environment(options=dummyopts, TOOLS=) 7 8 name = dummyenv['CONFIG'] 9 if not name: 10 return None 11 12 # Dynamically load the configuration module 13 name = 'build.config.' + name 14 __import__(name, dict(), dict()) 15 16 return sys.modules[name]
Then, for each setup file create the options, build environment, tests, etc.
1 for setupfile in setup: 2 3 config = DetectConfig(setupfile, ARGUMENTS) 4 if config is None: 5 # Raise error, or log error and continue with next setup 6 continue 7 8 # Create variables, first config-specific then the global ones 9 vars = config.Variables(setupfile, ARGUMENTS) 10 11 vars.Add(...) 12 13 # Create environment add do config-specific initialization from variables 14 # such as loading tools, setting build options, build flags, etc. Then do 15 # and global setup needed 16 env = config.Environment(vars) 17 18 ... 19 ... 20 21 # Running configure tests by getting them from the config module, passing in any extra 22 # tests needed globaly. The config module will run some config-specific tests and then 23 # return the Configure object for any more tests needed 24 conf = config.Configure(env, extra_tests) 25 26 conf.Check... 27 28 env = conf.Finish() 29 30 Export('env', 'config')
The config module's Environment and Configure functions may also add some helper methods to the base environment. It should use env.AddMethod and not AddMethod so that the method added will get rebound for any cloned environment. In addition other files may also add some helper methods.
The config module can set up into the environment which platform-specific code directory should be build, so the build system can then use that directory to build the platform specfic code library, and add a method for the later code to use that library:
1 Import('*') 2 3 # First build platform-dependent code library 4 # The SConscript file will add a method to the base environment 'SetupPlatformLibrary' 5 SConscript(env['PLATFORMDIR'] + '/SConscript') 6 7 # Next prepare and build main code 8 sources = Glob('*.c') 9 10 lenv = env.Clone() 11 lenv.SetupPlatformLibrary() 12 13 program = lenv.Program(sources) 14 15 # Remember the target for later packaging in the base environment 16 env['BUILDTARGETS']['program'] = program