Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scons construction environment inheritance

I'm having a bit of an issue refactoring a build system based on scons. We have a C/C++ source tree with several different output objects (dlls, executables, test executables), and a somewhat heterogeneous layout for our source files (although most of it is in 'module' directories with src/ and inc/ directories).

One of my biggest issues with the current setup is that we really want all of these build products to be built with consistent compiler options by default. Our current layout has a master SConstruct file calling many sub-SConscript files in subdirectories which then build pieces of the larger build products (.a's for example). By default, the SConscript() function in scons doesn't pass or inherit the current construction environment object to the called SConstruct file. That means that currently all of those sub-SConstript files are all using their own different construction environments.

The new layout I'm trying to put together has a master construction environment being put together at the source-tree root with all of the necessary CFLAGS and build defines that we need. I'd like this construction environment to be passed down to the sub-SConscript files so that I know that every single .c and .cpp file in our build tree is being built with the same command line.

I'm not sure how to do this in scons, though. There's the Import() and Export() functions, but those are basically ugly global variables - the calling SConstruct file doesn't have a lot of control over what the sub-SConstruct file does with the global variable that is Export()'ed. Is there any clean way essentially handing the sub-SConscript file the current construction environment as parameter, without letting it necessarily modify it? Something maybe like:

master_env = Environment()
master_env.Append( CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ] )

### add other stuff that we want everything to use

SConscript( 'somelibrary/SConstruct', inherited_environment=master_env.Clone() )

### master_env has now been used to build a 
### .dll in somelibrary/, but any variations
### made to somelibrary/SConstruct's inherited 
### env haven't contaminated master_env

I know that I could do something clumsy and sort of gross like this:

clobber_env = Environment()
master_env = Environment()
master_env.Append( CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ] )

call_somelibrary_sconstruct( master_env )

def call_somelibrary_sconstruct(env):
    param_env = env.Clone()
    Export( 'param_env' )
    SConstript( 'somelibrary/SConstruct' )

    # because we don't want any contamination of our global variable 
    # between SConscript calls. I'm not even sure if this is necessary
    # or does what I think it does because I'm not sure how this ugly
    # Export()'d global variable environment works with locals like 
    # param_env here.
    param_env = clobber_env
    Export( 'param_env' ) 

Is there an elegant way of doing this?

Update:

So I've played around with this some more, and it looks like as long as I do this in the master SConstruct file:

def build_somelib( env ):
    Export( env=env.Clone() )
    somelib = SConscript( 'somelib/SConscript' )
    return somelib

master_env = Environment()
master_env.Append( CXXFLAGS=['-Wall', '-Werror', '-g', '-fPIC', ... ] )

build_somelib( master_env )

and then in somelib/SConscript

Import( 'env' )
env.Append( CXXFLAGS=['-weirdoption1', ... ] )
lib = env.StaticLibrary( 'somelib', source=['source1.cpp', 'source2.cpp', ...] )
Return( "lib" )

then the master_env in the main SConstruct is left uncontaminated. It was important to me that the Export( env=env.Clone() ) work because I didn't want to rely on all the sub-SConscripts to do the safety-Clone()'ing - that policy should be parent SConscript/SConstruct files.

Still, it's a bit ugly to have to have env as a parameter name by policy.

like image 217
Ted Middleton Avatar asked Jul 17 '12 21:07

Ted Middleton


1 Answers

The best way I know of is from your master SConstruct just do this:

env = Environment()

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

Then in your src/SConscript file:

Import('env')

Then you can refer to the env variable as you would in your SConstruct file. If you don't want to mutate the SConstruct's env in src/SConscript, put this right after the Import:

env = env.Clone()

Pretty sure that's all there is to it.

like image 167
Tom Avatar answered Sep 21 '22 13:09

Tom