如何指定scons别名依赖项?

时间:2014-07-22 21:22:22

标签: python build scons

我有一个别名,可以构建一些名为'build_packages'的包。但是,除非在它之前构建特定的代码转换器库,否则不会构建此别名:'transcoderLib''transcoderLib'也是一个别名,并且自身构建得很好。我尝试指定我的别名依赖项,如下所示:

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

如果我构建'build_packages',则根本不构建'transcoderLib',并且构建失败,因为'build_packages'依赖于它。为什么scons没有接受依赖?

更多信息:在我声明这两个别名时,它们都没有任何目标,它们只是空的别名,稍后由SConscripts填充。我希望Depends('build_packages', 'transcoderLib')'build_packages'上定义来自'transcoderLib'的依赖关系,以便首先构建'transcoderLib',然后构建'build_packages'

编辑:为了增加这种混乱,我发现当我使用scons --tree=derived,prune时,它会打印出'build_packages'的所有正确依赖项!如果它看到依赖关系,为什么不建立它们?!!!这是构建树本身(当然是修剪,NDAs等):

+-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]

编辑3:为了提供一个更完整的例子,我安排了一个简单的SConstruct来模仿我相当好的情况(我在编辑2中删除了前面的例子以避免混淆)。真正的问题是Python文件正在导入'transcoderLib'目标,因此scons甚至不知道在构建包之前需要构建库。我试图告诉scons这是必要的。这是一个简单的例子:

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)

当然还有test.py,这是一个非常简单的脚本,依赖于bar.txt,'transcoderLib'的目标:

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

和输出:


scons: warning: Support for pre-2.7.0 Python version (2.6.2) is deprecated.
    If this will cause hardship, contact dev@scons.tigris.org.
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

当然,如果我首先使用transcoderLib',那么构建'bar.txt'就好了,我可以毫无错误地运行'scons config = 1'。对于那些想知道我为什么使用没有任何源或目标的构建器的人来说,这是为了让我的例子尽可能简单。 'package'构建器应该只运行'test.py'(实际上,它还构建了包,但包的依赖关系与'transcoderLib'完全隔离)。

2 个答案:

答案 0 :(得分:3)

如果我正确理解了您要实现的目标,那么您设置了错误的依赖项。我尝试从上面的EDIT 3修改您的SConstruct,如下所示:

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)

在尝试运行'package'步骤之前,它首先正确构建'bar.txt'。请注意,在更新时,“包”构建器会一次又一次地被调用,因为指定的目标“#Test”永远不会被创建...所以它总是被认为是过时的。

我希望这可以帮助您进一步,或者至少为您提供一些新的想法,如果这不是您一直在寻找的解决方案。

最后评论:只需将所需的依赖项集合添加到所有软件包中,方法是将其添加到包含软件包的Alias中,这将无效。你的Alias被认为是一个不同的目标,所以如果你调用“scons package_1”来构建一个包...依赖项将不会启动。你必须明确并将依赖项添加到每个包中,因为这就是你的构建结构看起来像。

答案 1 :(得分:1)

显然env.Alias()设置依赖关系,而不是等效关系。所以当你说build_packages依赖于transcoderLib时,你说bar.txt也依赖于transcoderLib。

考虑您的简单示例生成的树:

$ 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

正如您所看到的,由于build_packages电话,bar.txt取决于env.Alias()。由于build_packages来电,transcoderLib也取决于Depends()。但bar.txttranscoderLib之间没有任何关系。

如果bar.txt 依赖于transcoderLib,则需要表达该关系:

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

如果该行已添加到您的示例中,则生成的树为:

$ 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