Scons 循环依赖

Scons Cyclic Dependency

我们从 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 片段如下:

 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
 )

一些内联问题。在上面的评论部分不容易做到.. (见下面的 ## 评论)

 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
 )

我能够找到问题所在,但我不确定这是否是 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 中有没有办法说我依赖于源文件,而不是目标文件?或者这是循环依赖中的bug/nuance?