[Scons-users] Advice sought
Dominic Binks
dominic.binks at thebinkles.net
Sat Feb 7 16:16:05 EST 2015
Hi all,
I'm looking for some expert advice on how to go about implementing (well
technically modifying) a build system to achieve a separated host and
target build output.
I'm aware of the 'stock' answer of calling SConscript() twice, once for
the host and once for the target. That doesn't meet my needs because
the rest of the SConscripts will be a nightmare to maintain for the
following reasons.
We have a number of different binaries we build, some of which are only
targeted to the host side, some only for the target side and some get
compiled for both.
In a typical deployment, we're often working with both linux platforms
for host and target with the host being x86 and target being ARM. Some
of the ARM targets we work with use bare-metal toolchains and are not
capable of building executables.
This means that, should I adopt the call SConscript twice I'll end up
with every single target I need to build having to do something like:
if target_env:
obj1 = env.Object()
obj2 = env.Object()
if target is not bare_metal:
prog1 = env.Program()
if host_env:
obj3 = env.Object()
obj4 = env.Object()
prog2 = env.Program()
which I really don't like. When this combined with other conditional
parts of the build system will get very messy, very quickly.
The Android build system which is based on make has quite a clean way of
doing this. I imagined that VariantDir() would help me out here but
reading more about it, it doesn't really do what I need.
What I'd like to be able to do is to have two environments that I can
pass around that represent the host and the target builds (say host_env
for the host environment and target_env for the target environment) and
do things like this
obj1 = target_env.Object()
obj2 = target_env.Object()
if target is not bare_metal:
prog1 = target_env.Program()
obj3 = host_env.Object()
obj4 = host_env.Object()
prog2 = host_env.Program()
I've managed to achieve something like this with the following approach
- I'm not that happy with it but it works. I wondered if anyone had any
better suggestions on how I could handle this.
Essentially I wrap the calls to Object to manipulate the target paths
based on values from the environment (target or host). While I didn't
do this above, I could use the same effect to avoid trying to build
programs for targets that use bare-metal toolchains as well.
SContruct
-----
env = Environment()
henv = env.Clone()
henv.VariantDir("build/host", "src")
henv["CCCOMSTR"] = "HOST CC $SOURCE"
tenv = env.Clone()
tenv.VariantDir("build/target", "src")
tenv["CCCOMSTR"] = "TARGET CC $SOURCE"
tenv["CCFLAGS"] = ["-Os"]
henv.SConscript("src/SConscript", exports=['env','henv','tenv'],
duplicate=0)
Import('all')
env.Default(all)
-----
src/SConscript
-----
import os
Import('henv', 'tenv', 'env')
def hostobj(target, sources):
return henv.Object(
os.path.join("#build/host/",
str(henv.File(sources[0]).dir),target), sources)
def targobj(target, sources):
return tenv.Object(
os.path.join("#build/target/",
str(tenv.File(sources[0]).dir),target), sources)
host_foo = hostobj('foo', ['foo.c'])
targ_foo = targobj('foo', ['foo.c'])
targ_bar = targobj('bar', ['othersrc/bar.c'])
all = env.Alias([host_foo,targ_foo,targ_bar])
Export('all')
-----
For what it's worth all the referenced C files are just empty files.
This gives me output that looks like this:
build/
build/host
build/host/foo.o
build/target
build/target/othersrc
build/target/othersrc/bar.o
build/target/foo.o
I can then assemble a package using a combination of host and target
binaries to send to customers from the output of the build.
Is this the best way to do this? Can the output path (i.e. "build") be
a callable that can reference the environment?
I don't really want to have to wrap all the builders in the environment
to facilitate this.
Many thanks
Dominic
More information about the Scons-users
mailing list