Darkhydro
Darkhydro

Reputation: 2072

How do I specify scons alias dependencies?

I have an alias that builds some packages, called 'build_packages'. This alias won't build, however, unless a specific transcoder library is built before it: 'transcoderLib'. 'transcoderLib' is an alias as well, and builds just fine by itself. I tried specifying my alias dependencies like so:

env.Alias('transcoderLib')
...
Default(env.Alias('build_packages'))
Depends('build_packages', 'transcoderLib')

If I then build 'build_packages', 'transcoderLib' is not built at all and the build fails, since 'build_packages' depends on it. Why is scons not picking up the dependency?

Further information: At the point where I declare both of these aliases, neither of them has any targets yet, they are simply empty aliases which are filled by SConscripts later. I expect Depends('build_packages', 'transcoderLib') to define a dependency from 'build_packages' on 'transcoderLib', so that 'transcoderLib' is built first and then 'build_packages' is built.

EDIT: To add to this confusion, I found that when I used scons --tree=derived,prune, it prints out all the correct dependencies for 'build_packages'! If it sees the dependencies, why isn't it building them?!!! Here is the build tree itself (pruned of course, NDAs and such):

+-build_packages
  +-Build\Config\Package_1
  | +-Package_1_Dependencies...
  +-Build\Config\Package_2
  | +-Package_2_Dependencies...
  ...etc... for 16+ packages...
  +-transcoderLib
    +-Build\Transcoder.dll
    | +-DLL dependencies...
    +-Build\Transcoder.lib
    | +-LIB dependencies
    +-Build\Transcoder.exp
    | +-EXP depdendencies
    +-Lib\Python\Transcoder.pyd
      +-[Build\Transcoder.dll]
      +-[Build\Transcoder.lib]
      +-[Build\Transcoder.exp]

EDIT 3: To provide a more complete example, I've arranged a simple SConstruct that mimicks the situation I have rather well (I deleted the previous example in EDIT 2 to avoid confusion). The real problem is that a Python file is importing the 'transcoderLib' target, so scons doesn't even know it needs to build the library before building packages. I'm trying to tell scons it is necessary. Here's the simple example:

import SCons
import shutil
import os

env = Environment(tools=['default', 'textfile'])

def package_builder(target, source, env):
  cmdLine = 'python test.py'
  return os.system(cmdLine)

def copy(env, target, source):
  shutil.copy(source[0].path, target[0].path)
env.Append(BUILDERS = { 'copybuilder' : Builder(action = Action(copy, ' COPY $SOURCE -> $TARGET')) } )
env.Append(BUILDERS = { 'package' : Builder(action = Action(package_builder, ' PACKAGE $SOURCES -> $TARGET'), suffix='.zip' ) } )

env.Textfile(target='foo.txt', source='hello, world\n')

config = int(ARGUMENTS.get('config', 0))
if config == 1:
  Default(env.Alias('build_packages'))
  Depends(env.Alias('build_packages'), env.Alias('transcoderLib'))

env.Alias('transcoderLib', 'foo.txt')
copyTarget = env.copybuilder('bar.txt', 'foo.txt')
env.Alias('transcoderLib', copyTarget)

package = env.package('#Test', [])
env.Alias('build_packages', package)

and of course test.py, which is an extremely simple script that depends on bar.txt, the target of 'transcoderLib':

import os
if not os.path.exists('bar.txt'):
  raise Exception("bar.txt wasn't created yet!")

and the output:


scons: warning: Support for pre-2.7.0 Python version (2.6.2) is deprecated.
    If this will cause hardship, contact [email protected].
File "C:\Python26\Scripts\scons.py", line 192, in 
scons: Building targets ...
 PACKAGE  -> Test.zip
Traceback (most recent call last):
  File "test.py", line 3, in 
    raise Exception("bar.txt wasn't created yet!")
Exception: bar.txt wasn't created yet!
scons: *** [Test.zip] Error 1

Of course, if I 'scons transcoderLib' first, it builds 'bar.txt' just fine, and I can run 'scons config=1' without error. For those wondering why I'm using a builder without any sources or targets, it's to keep my example as simple as possible. The 'package' builder should simply run 'test.py' (in reality, it also builds the package, but the package's dependencies are completely isolated from the 'transcoderLib').

Upvotes: 0

Views: 3167

Answers (2)

dirkbaechle
dirkbaechle

Reputation: 4052

You setup wrong dependencies, if I understood correctly what you're trying to achieve. I tried to amend your SConstruct from EDIT 3 above, as follows:

import SCons
import shutil
import os

env = Environment(tools=['default', 'textfile'])

def package_builder(target, source, env):
  cmdLine = 'python test.py'
  return os.system(cmdLine)

def copy(env, target, source):
  shutil.copy(source[0].path, target[0].path)
env.Append(BUILDERS = { 'copybuilder' : Builder(action = Action(copy, ' COPY $SOURCE -> $TARGET')) } )
env.Append(BUILDERS = { 'package' : Builder(action = Action(package_builder, ' PACKAGE $SOURCES -> $TARGET'), suffix='.zip' ) } )

env.Textfile(target='foo.txt', source='hello, world\n')

#
# Here the changes start
#

# The following line is not needed, SCons picks up the
# dependency bar.txt -> foo.txt automatically
#tclib = env.Alias('transcoderLib', 'foo.txt')
copyTarget = env.copybuilder('bar.txt', 'foo.txt')
# Defining Alias for later reference...
# important: don't create new Alias()es all over
#            the place, but pass a single reference around
tclib = env.Alias('transcoderLib', copyTarget)

# Main change: Your initial dependencies were wrong, it's
# the package (='python test.py') that depends on your
# transcoderLib (='bar.txt')...
package = env.package('#Test', [])
env.Depends(package, tclib)

# Create an Alias for the packages, you can pass
# a list of all your packages too here...
bp = env.Alias('build_packages', package)

# Finally, set the package Alias() as default target if
# requested by the config parameter...
config = int(ARGUMENTS.get('config', 0))
if config == 1:
  env.Default(bp)

It correctly builds 'bar.txt' first, before trying to run the 'package' step. Note that on an update, the 'package' Builder gets called again and again, because the specified target "#Test" never gets created...so it's always regarded to be out-of-date.

I hope this helps you further, or at least gives you a few new ideas if this isn't the solution you've been looking for.

Final remark: Simply adding a required dependency collectively to all your packages, by adding it to an Alias that contains your packages, won't work. Your Alias is regarded as a different target, so if you call "scons package_1" to build a single package...the dependency won't kick in. You have to be explicit and add the dependency to each package, because that's how your build structure looks like.

Upvotes: 4

Robᵩ
Robᵩ

Reputation: 168626

Apparently env.Alias() sets up a dependency, not an equivalency. So when you say that build_packages depends upon transcoderLib, you are not saying that bar.txt also depends upon transcoderLib.

Consider the tree that your simple example produces:

$ scons -n -Q --tree=all -f ex.sc config=1
scons: `build_packages' is up to date.
+-build_packages
  +-bar.txt
  | +-hello, world

  +-transcoderLib
    +-foo.txt
      +-hello, world

As you can see, build_packages depends upon bar.txt due to the env.Alias() call. build_packages also depends upon transcoderLib, due to the Depends() calls. But there is no relationship between bar.txt and transcoderLib.

If bar.txt does depend upon transcoderLib, then that relationship needs to be expressed:

Depends('bar.txt', env.Alias('transcoderLib'))

If that line is added to your example, the resulting tree is:

$ scons -Q --tree=all -f ex1.sc config=1
scons: `build_packages' is up to date.
+-build_packages
  +-bar.txt
  | +-hello, world

  | +-transcoderLib
  |   +-foo.txt
  |     +-hello, world

  +-transcoderLib
    +-foo.txt
      +-hello, world

Upvotes: 1

Related Questions