【问题标题】:Scons Cyclic DependencyScons 循环依赖
【发布时间】:2016-12-19 18:05:42
【问题描述】:

我们从 scons 2.4.1 更新到 2.5.1 并突然出现如下几个错误: scons: *** 找到依赖循环: 内部错误:找不到节点的循环...

我认为该问题与我们尝试自动更新的版本文件有关,如果我们的 SCM 检测到对源文件的编辑。该过程的要点是我们维护一个具有#defines 的文件“version.cfg”。该文件被检入我们的 SCM。如果文件已经更新过一次,则在文件提交到 SCM 之前不会再次更新。然后使用该文件自动生成名为“kb_version.hh”的 C++ 头文件。

什么是循环依赖,如何消除它? (注意,无论是什么问题,在 scons 2.4.1 中都没有引起问题(只有当我们使用新版本 2.5.1 时,它才会检测到循环依赖)。

相关的scons sn-p如下:

 SRCDIR = '../../src'

 SRCS = [
   'kb.cc',
 ]

 SOURCE = [ os.path.join(SRCDIR, s) for s in SRCS ]

 SCRIPT_VERSION_GEN = os.path.join(env['_ROOT'], 'kb/build/scripts/versionGen.sh')
 SCRIPT_VERSION_UPD = os.path.join(env['_ROOT'], 'kb/build/scripts/versionUpdate.sh')

 FILE_VERSION_CFG = 'version.cfg'
 FILE_VERSION_HH  = 'kb_version.hh'

 scriptVerGen = env.File(SCRIPT_VERSION_GEN)
 scriptVerUpd = env.File(SCRIPT_VERSION_UPD)
 verCfg = env.File(os.path.join(SRCDIR, FILE_VERSION_CFG))
 verHH  = env.File(os.path.join(SRCDIR, FILE_VERSION_HH))

 ## this command detects for change in source files, then updates, when necessary, the source version.cfg
 env.Command(
   target = verCfg,
   source = [ SOURCE, scriptVerUpd ],
   action = [ scriptVerUpd.path + ' ' + env['BS_DIR_SRCROOT'] + '/kb/foo' + verCfg.srcnode().path, Copy(verCfg.path, verCfg.srcnode().path) ]
 )

 env.Command(
   target = verHH,
   source = [ verCfg, scriptVerGen ],
   action = scriptVerGen.path + ' ' + verHH.path + ' ' + verCfg.path
 )

【问题讨论】:

  • 2.5 版增强了依赖项扫描机制,如果您阅读发行说明,您会看到可能会发现新依赖项的说明。在您的情况下,循环依赖似乎很可能是通过 SCons 中增强逻辑的新发现的依赖找到的。

标签: scons


【解决方案1】:

几个内联问题。在上面的 cmets 部分中不容易做到.. (参见下面的## cmets)

 SRCDIR = '../../src'

 SRCS = [
   'kb.cc',
 ]

 SOURCE = [ os.path.join(SRCDIR, s) for s in SRCS ]


 ## Is _ROOT the top of your tree where SConstruct lives?
 SCRIPT_VERSION_GEN = os.path.join(env['_ROOT'], 'kb/build/scripts/versionGen.sh')
 SCRIPT_VERSION_UPD = os.path.join(env['_ROOT'], 'kb/build/scripts/versionUpdate.sh')

 FILE_VERSION_CFG = 'version.cfg'
 FILE_VERSION_HH  = 'kb_version.hh'

 scriptVerGen = env.File(SCRIPT_VERSION_GEN)
 scriptVerUpd = env.File(SCRIPT_VERSION_UPD)
 verCfg = env.File(os.path.join(SRCDIR, FILE_VERSION_CFG))
 verHH  = env.File(os.path.join(SRCDIR, FILE_VERSION_HH))

 ## this command detects for change in source files, then updates, when necessary, the source version.cfg
 env.Command(
   target = verCfg,
   source = [ SOURCE, scriptVerUpd ],

   ## Why not do this?
   action = [ '$SCRIPT_VERSION_UPD $BS_DIR_SRCROOT /kb/foo ' + verCfg.srcnode().path,  ## Why srcnode()?
              ## Why do this? 
              Copy(verCfg.path, verCfg.srcnode().path) ]
 )

 env.Command(
   target = verHH,
   source = [ verCfg, scriptVerGen ],  
   ## How about this change
   action = '$SCRIPT_VERSION_GEN $TARGET' + verCfg.path
 )

【讨论】:

  • 1) _ROOT 只是我们在 SCONS env 中设置的 shell 环境变量,它是源代码树的根路径。 SConstruct 位于该树中的一个子目录中(根据正在构建的项目,我们有多个 SConstructs)。我们使用 -C 选项调用 scons。 2) 如果我们的 scm 检测到代码库的某个区域中的文件已更改,我们正在尝试更新 version.cfg。检测逻辑在脚本 $SCRIPT_VERSION_UPD 中。该文件需要更新然后签入 SCM,因此我们希望在 srcnode 应用更改,而不是在变体 dir 位置。
  • 我尝试了您建议的更改,效果是一样的,正如我预测的那样,因为我们只是说同样的事情不同。
  • 为什么会在出现以下情况时产生循环依赖“故障”: 文件S #includes 文件V(因此文件S依赖文件V) 文件V依赖文件C 文件C依赖在文件 S 上(但只有 S 的 md5,所以如果 V 发生变化,S 不应被视为修改,因为它与 C 相关)
  • 你如何得到一个文件A,它只依赖于另一个文件(B)的MD5,而A实际上不依赖于B?
  • 啊。行。我觉得我懂了。您需要使用 env.Ignore(A,[list of all B's include/implicit dependencies])。看看:scons.org/doc/production/HTML/scons-man.html#f-ignore
【解决方案2】:

我能够找到问题所在,但我不确定这是否是 scons 的理想行为。

问题是这样的。 (1) C++源文件依赖version.h(通过#include的方式) (2) version.h 是从 version.cfg 自动生成的 (3) 如果任何源文件已更新,version.cfg 会自动递增,其中包括依赖于 version.h 的源文件(因此是循环依赖)。但是,c++ 源文件可能不会发生实际更改,但文件本身 #includes version.h。所以我们的意图是,当且仅当源文件本身发生变化时,version.cfg 应该被更新(而不是编译源文件产生的目标文件)。

在下面的评论中,可以通过从第一个 env.Command() 调用中的“source =”行中删除 SOURCE 变量来消除循环依赖。

scons 中有没有办法说我依赖源文件,而不是目标文件?或者这是循环依赖中的错误/细微差别?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-01
    • 1970-01-01
    • 2010-09-12
    • 2021-10-02
    • 1970-01-01
    相关资源
    最近更新 更多