[Scons-users] Modifying the provided environment in an emitter?
Marc Branchaud
marcnarc at xiplink.com
Mon Apr 24 11:38:52 EDT 2017
On 2017-04-21 05:29 PM, Andrew C. Morrow wrote:
>
> Hi all -
>
> Is it legit to modify the passed in env in an emitter?
I dunno about "legit" but we do this all the time when we want to pass
info calculated in the emitter to the builder.
Here's a simple example: One of the things we build is a complete OS
image in a variant subdir (which we then bundle into a tarball). The OS
image contains symlinks to absolute paths, which are legitimate when the
image is written onto a root partition, but which are "dead" (the
symlink's source doesn't exist) when they are in the image's variant subdir.
So we have a SymLink Builder that lets us create these symlinks:
SymLink(target="name/of/symlink/in/os/image",
source="/absolute/path/of/symlink/source")
Since the Builder's source isn't an actual file, the emitter sets the
source to None, so that SCons ignores it. But we need to save that
source path to create the actual symlink, so we store it in a dict in
the environment. The dict is keyed by the target's variant-dependent
absolute path. (This emitter also works with non-absolute-path symlink
sources, by stripping the path that SCons prepends to such things.)
def emitter(target, source, env):
if '__SymLinkSources' not in env.Dictionary():
env['__SymLinkSources'] = {}
# The source of a symlink is just an arbitrary
# string, but SCons thinks it's a file and so
# prepends it with the path to the SConscript
# that uses the SymLink builder. Undo this.
path = env.Dir('.').srcnode().abspath
src = str(source[0])
if src.startswith(path):
src = src[len(path)+1:]
env['__SymLinkSources'][target[0].abspath] = src
return (target, None)
Then the builder simply extracts the source path from the dict:
def builder(target, source, env):
# SCons can't tell the difference between a
# symlink that points to an non-existent file
# and a symlink that doesn't even exist.
# So we need to be smart here, because we
# might be asked to re-create a symlink that's
# already there.
tgt = target[0].abspath
if os.path.lexists(tgt):
# If the target already exists, just remove it.
os.unlink(tgt)
os.symlink(env['__SymLinkSources'][tgt], tgt)
Several of our Builders do this sort of thing. Works great!
M.
> def add_lib_foo_emitter(target, source, env):
> libs = env.get('LIBS', [])
> libs.append('foo')
> env['LIBS'] = libs
> return (target, source)
>
> def add_emitter(builder):
> base_emitter = builder.emitter
> new_emitter = SCons.Builder.ListEmitter([add_lib_foo_emitter,
> base_emitter])
> builder.emitter = new_emitter
>
> target_builders = ['Program', 'SharedLibrary', 'LoadableModule',
> 'StaticLibrary']
> for builder in target_builders:
> add_emitter(env['BUILDERS'][builder])
>
> I've found myself wanting to do this with increasing frequency, but am
> unclear on whether this is acceptable. It appears to work, but the
> documentation doesn't seem to offer any clear guidance that I've found
> on whether it is guaranteed to work. If so (which would be great!), am I
> guaranteed that the modification of env is scoped only to the passed in
> targets?
>
> Thanks,
> Andrew
>
>
>
> _______________________________________________
> Scons-users mailing list
> Scons-users at scons.org
> https://pairlist4.pair.net/mailman/listinfo/scons-users
>
More information about the Scons-users
mailing list