[Scons-users] Custom builder

Dirk Bächle tshortik at gmx.de
Sat Sep 8 06:29:27 EDT 2012

Hi Bill,

I think I found something.

On 07.09.2012 11:00, William Roberts wrote:

> I am having issues wrapping a custom builder in a custom class.


> Suppose I have the following SConstruct file that calls a SConscript file:


> #Miniat is my custom wrapper for building

> miniat = MiniatBuilder(rootdir, libdir, exedir, env, q)

> SConscript(script, variant_dir=q, duplicate=1, exports=[ 'miniat' ] )


> Then in the SConscript file, I do something like:


> f = miniat.flex('src/lex.yy.c', 'src/0x1_assembler.lex')


> In the MiniatBuilder constructor I do:


> self._env = env

> bld = self._env.Builder(action = 'flex -i -o $TARGET $SOURCE',

> src_suffix = '.lex')

> self._env['BUILDERS']['Flex'] = bld


> I get the following output:


> flex -i -o

> flex: option `o' requires an argument

> Try `flex --help' for more information.

When you say "env.Builder(action = 'flex -i -o $TARGET $SOURCE')", SCons
substitutes the variables immediately. Since no target or source are
given at this point in time, they end up in empty strings and the Action
fails later on.

> But if I take that same code, and append to the enviroment in the

> SConscript file, it works:


> Import('miniat')


> env = miniat._env

> bld = Builder(action = 'flex -i -o $TARGET $SOURCE',

> src_suffix = '.flex')

> env.Append(BUILDERS = {'Flex' : bld})


> f = env.Flex('src/lex.yy.c', 'src/0x1_assembler.lex')


> Can someone please shed some light?

Here you use the "Builder()" method from the "DefaultEnvironment" which
doesn't aggressively substitute things, but waits until the Action is
executed to create the target. That's why this approach works. For the
fun of it, just try to replace the "Builder" line with

bld = env.Builder(action = ...)

and it chokes again. ;)

Internally, the "Builder()" method is a convenient wrapper for writing:

import SCons.Builder

bld = SCons.Builder.Builder(action = "")

, which is my preferred method of setting up Builders and Actions for
new Tools. Have a peek at our Tool writing guide at


if you find the time.

Finally, a few comments regarding your current build setup for "miniat".
I looked at the sources and noticed the following:

- Scanning for "SConscript"s and processing them automatically can
lead to problems, because the
os.walk() will find leftover SConscripts in your "out" directory too.
It might be better to keep things explicit and have a list of names
for the SConscripts to be processed.
- By wrapping the build environment and its builders into your
MiniatBuilder you are restricted to one build
environment per "module", so to speak. What happens later on, if
you find that you need special compile
options in one of your subfolders? How do you plan to support
"release vs. debug" builds?
It's okay to keep track of metadata like paths and names/keys for
the single modules, but I wouldn't add
the build environment to this mix. Simply set it up in your
top-level SConstruct and pass it on to your
SConscripts with the Export/Import mechanism.
In the SConscripts you can use the environment as-is and don't have
to care about whether it is a "debug" or
"release" build. And if required, simply create a local clone with
env.Clone() and add special compile flags, such
that the global env stays clean.

Best regards,


More information about the Scons-users mailing list