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 an SConscript
file
so they can be imported by other
SConscript
files, thus allowing you to share common initialized
values throughout your build hierarchy.
There are two ways to export a variable
from an SConscript
file.
The first way is to call the Export
function.
Export
is pretty flexible - in the simplest form,
you pass it a string that represents the name of
the variable, and Export
stores that with its value:
env = Environment() Export('env')
You may export more than one variable name at a time:
env = Environment() debug = ARGUMENTS['debug'] Export('env', 'debug')
Because a Python identifier cannot contain spaces,
Export
assumes a string containing spaces is is a
shortcut for multiple variable names to export and
splits it up for you:
env = Environment() debug = ARGUMENTS['debug'] Export('env debug')
You can also pass Export
a dictionary of values.
This form allows the opportunity to export a variable
from the current scope under a different name -
in this example, the value of foo
is exported under the name "bar"
:
env = Environment() foo = "FOO" args = {"env": env, "bar": foo} Export(args)
Export
will also accept arguments in keyword style.
This form adds the ability to create exported variables
that have not actually been set locally in the SConscript file.
When used this way, the key is the intended variable name,
not a string representation as with the other forms:
Export(MODE="DEBUG", TARGET="arm")
The styles can be mixed, though Python function calling syntax requires all non-keyword arguments to precede any keyword arguments in the call.
The Export
function adds the variables to a global
location from which other SConscript
files can import.
Calls to Export
are cumulative. When you call Export
you are actually updating a Python dictionary, so it
is fine to export a variable you have already exported,
but when doing so, the previous value is lost.
The other way to export is you can specify a list of
variables as a second argument
to the SConscript
function call:
SConscript('src/SConscript', 'env')
Or (preferably, for readability) using the exports
keyword argument:
SConscript('src/SConscript', exports='env')
These calls export the specified variables
to only the listed SConscript
file(s).
You may 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.
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 previously defined env
variable available to the SConscript
file.
Assuming env
is a construction environment,
after import it can be used to build programs, libraries, etc.
The use case of passing around a construction environment is extremely common
in larger scons builds.
Like the Export
function,
the Import
function can be called
with multiple variable names:
Import('env', 'debug') env = env.Clone(DEBUG=debug) env.Program('prog', ['prog.c'])
In this example, we pull in the common construction environment
env
, and
use the value of the debug
variable to make a modified copy by passing
that to a Clone
call.
The Import
function will (like Export
)
split a string containing white-space
into separate variable names:
Import('env debug') env = env.Clone(DEBUG=debug) env.Program('prog', ['prog.c'])
Import
prefers a local definition to a global one,
so that if there is a global export of foo
,
and the calling SConscript has
exported foo
to this SConscript,
the import will find the foo
exported to this SConscript.
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 up to date in each 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 object files built by
several subsidiary SConscript
files.
You can do this by using the Return
function to return values
from the subsidiary SConscript
files
to the calling file. Like Import
and Export
,
Return
takes a string representation of the variable
name, not the variable name itself.
If, for example, we have two subdirectories
foo
and bar
that should each contribute an object
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