14.5. Sharing Environments (and Other Variables) Between SConscript Files

In the previous example, each of the subsidiary SConscript files created its own construction environment by calling Environment separately. This obviously works fine, but if each program must be built with the same construction variables, it's cumbersome and error-prone to initialize separate construction environments in the same way over and over in each subsidiary SConscript file.

SCons supports the ability to export variables from a parent SConscript file to its subsidiary SConscript files, which allows you to share common initialized values throughout your build hierarchy.

14.5.1. Exporting Variables

There are two ways to export a variable, such as a construction environment, from an SConscript file, so that it may be used by other SConscript files. First, you can call the Export function with a list of variables, or a string of white-space separated variable names. Each call to Export adds one or more variables to a global list of variables that are available for import by other SConscript files.


        env = Environment()
        Export('env')
      

You may export more than one variable name at a time:


        env = Environment()
        debug = ARGUMENTS['debug']
        Export('env', 'debug')
      

Because white space is not legal in Python variable names, the Export function will even automatically split a string into separate names for you:


        Export('env debug')
      

Second, you can specify a list of variables to export as a second argument to the SConscript function call:


        SConscript('src/SConscript', 'env')
      

Or as the exports keyword argument:


        SConscript('src/SConscript', exports='env')
      

These calls export the specified variables to only the listed SConscript files. You may, however, specify more than one SConscript file in a list:


        SConscript(['src1/SConscript',
                    'src2/SConscript'], exports='env')
      

This is functionally equivalent to calling the SConscript function multiple times with the same exports argument, one per SConscript file.

14.5.2. Importing Variables

Once a variable has been exported from a calling SConscript file, it may be used in other SConscript files by calling the Import function:


        Import('env')
        env.Program('prog', ['prog.c'])
      

The Import call makes the env construction environment available to the SConscript file, after which the variable can be used to build programs, libraries, etc.

Like the Export function, the Import function can be used with multiple variable names:


        Import('env', 'debug')
        env = env.Clone(DEBUG = debug)
        env.Program('prog', ['prog.c'])
      

And the Import function will similarly split a string along white-space into separate variable names:


        Import('env debug')
        env = env.Clone(DEBUG = debug)
        env.Program('prog', ['prog.c'])
      

Lastly, as a special case, you may import all of the variables that have been exported by supplying an asterisk to the Import function:


        Import('*')
        env = env.Clone(DEBUG = debug)
        env.Program('prog', ['prog.c'])
      

If you're dealing with a lot of SConscript files, this can be a lot simpler than keeping arbitrary lists of imported variables in each file.

14.5.3. Returning Values From an SConscript File

Sometimes, you would like to be able to use information from a subsidiary SConscript file in some way. For example, suppose that you want to create one library from source files scattered throughout a number of subsidiary SConscript files. You can do this by using the Return function to return values from the subsidiary SConscript files to the calling file.

If, for example, we have two subdirectories foo and bar that should each contribute a source file to a Library, what we'd like to be able to do is collect the object files from the subsidiary SConscript calls like this:


          env = Environment()
          Export('env')
          objs = []
          for subdir in ['foo', 'bar']:
              o = SConscript('%s/SConscript' % subdir)
              objs.append(o)
          env.Library('prog', objs)
      

We can do this by using the Return function in the foo/SConscript file like this:


          Import('env')
          obj = env.Object('foo.c')
          Return('obj')
        

(The corresponding bar/SConscript file should be pretty obvious.) Then when we run SCons, the object files from the subsidiary subdirectories are all correctly archived in the desired library:


        % scons -Q
        cc -o bar/bar.o -c bar/bar.c
        cc -o foo/foo.o -c foo/foo.c
        ar rc libprog.a foo/foo.o bar/bar.o
        ranlib libprog.a