【问题标题】:How does Scons compute the build signature?Scons 如何计算构建签名?
【发布时间】:2016-02-20 09:08:09
【问题描述】:

我将一个项目的不同版本保存在不同的目录中。 (这确实在这个项目中有意义。可悲的是。)由于版本之间只有微小的差异,我希望我可以通过为所有构建使用公共缓存目录来加快第一个构建之后的所有构建。

不幸的是,我不得不意识到,当从不同目录中的相同源构建目标文件时,SCons 2.3.3 将结果存储在缓存中的不同位置。 (我假设该位置等于构建签名。)为每个目录重新编译相同的源。那么为什么 SCons 会确定不同的构建签名虽然

  • 编译命令是相同的并且
  • 源文件和包含文件相同(预处理器阶段的相同输出,gcc -E ...
  • 我正在使用判定器“MD5-timestamp”

甚至生成的目标文件都是相同的!

举一个简单的例子(来自 SCons 文档的helloworld),重用缓存是可行的。虽然在我正在从事的大项目中,但事实并非如此。也许“SCons 构建环境”会影响构建签名,即使它对编译命令没有任何影响?

除了--cache-debug=- 之外,还有什么调试选项可以提供帮助吗? SCons 的哪种方法确定构建签名?

文件夹看起来有点像这样:

<basedir1>/
       SConstruct
       src/something.cpp …
       include/header.hpp …
<basedir2>/
       SConstruct
       src/something.cpp …
       include/header.hpp …
/SharedCache/
       0/ 1/ 2/ … F/

我在 basedir1basedir2 中都检查了该项目,并在这两个中都调用了scons --build-cache-dir=/SharedCache。 (编辑:--build-cache-dir 是一个自定义选项,在该项目的SConstruct 文件中实现。它映射到env.CacheDir('/SharedCache')

EDIT2:在我意识到这个问题之前,我做了一些测试来评估使用--cache-implicit 或 SCons 2.4.0 的效果。

【问题讨论】:

  • 你能粘贴一个示例编译命令行吗?尝试 --debug=explain 也。可能您在命令行中有部分路径,其中包含的路径多于相对路径。因此命令行是不同的。 (我注意到你在 scons 用户邮件列表上也有一个关于这个问题的活跃问题)
  • 我重新验证了编译命令是相同的。每一点。这是一个简写示例:g++ -o &lt;target&gt;.o -c -m64 -I&lt;global_include_path&gt; -fmessage-length=0 -D_LARGEFILE64_SOURCE … -fno-strict-aliasing -Wall -Werror -Wsign-promo … -DXOC_FILE_ID=\"ProtocolUnitTester:ate_ext_td_ProtocolFrameworkTests_generated.cpp\" -fPIC -Iinclude -Iinclude-uda -I. &lt;src&gt;.cpp.
  • 通过“当从不同目录中的相同源构建目标文件时,SCons 2.3.3 将结果存储在缓存中的不同位置。”您的意思是源位于 SConstruct 下的不同目录中吗?或者您的意思是 SConstruct 下的目录结构相同,但 SConstruct 的基本目录是唯一不同的东西?所以 /a/b/c/abc.c 和 /a/b/d/abc.c 或 /a/b/c/abc.c 和 /a/b /c/abc.c 其中 SConstruct 在 basedir 中。
  • @bdbaddog 这是 /a/b/c/abc.c 和 /a/b/c/abc.c。
  • SCons 中不存在命令行参数--build-cache-dir,无论是在 v2.3.5 中还是在最新的主干中。当我在每个 SConstruct 中明确指定缓存目录时,一切都会按预期工作。根据您迄今为止提供的信息和示例,我无法重现我这边的问题...

标签: scons


【解决方案1】:

这是来自文件src/engine/SCons/Node/FS.py的方法get_cachedir_bsig()的代码:

def get_cachedir_bsig(self):
    """
    Return the signature for a cached file, including
    its children.

    It adds the path of the cached file to the cache signature,
    because multiple targets built by the same action will all
    have the same build signature, and we have to differentiate
    them somehow.
    """
    try:
        return self.cachesig
    except AttributeError:
        pass

    # Collect signatures for all children
    children = self.children()
    sigs = [n.get_cachedir_csig() for n in children]
    # Append this node's signature...
    sigs.append(self.get_contents_sig())
    # ...and it's path
    sigs.append(self.get_internal_path())
    # Merge this all into a single signature
    result = self.cachesig = SCons.Util.MD5collect(sigs)
    return result

它显示了缓存文件的路径如何包含在“缓存构建签名”中,它解释了您看到的行为。为了完整起见,这里也是来自同一个FS.py 文件的get_cachedir_csig() 方法的代码:

def get_cachedir_csig(self):
    """
    Fetch a Node's content signature for purposes of computing
    another Node's cachesig.

    This is a wrapper around the normal get_csig() method that handles
    the somewhat obscure case of using CacheDir with the -n option.
    Any files that don't exist would normally be "built" by fetching
    them from the cache, but the normal get_csig() method will try
    to open up the local file, which doesn't exist because the -n
    option meant we didn't actually pull the file from cachedir.
    But since the file *does* actually exist in the cachedir, we
    can use its contents for the csig.
    """
    try:
        return self.cachedir_csig
    except AttributeError:
        pass

    cachedir, cachefile = self.get_build_env().get_CacheDir().cachepath(self)
    if not self.exists() and cachefile and os.path.exists(cachefile):
        self.cachedir_csig = SCons.Util.MD5filesignature(cachefile, \
            SCons.Node.FS.File.md5_chunksize * 1024)
    else:
        self.cachedir_csig = self.get_csig()
    return self.cachedir_csig

子节点的缓存路径被散列到最终构建签名中。

编辑: 上面计算的“缓存构建签名”然后用于构建“缓存路径”。像这样,所有文件/目标都可以映射到唯一的“缓存路径”,通过它可以在缓存中引用和找到它们(=从缓存中检索)。正如上面的 cmets 所解释的,每个文件的相对路径(从 SConstruct 的顶级文件夹开始)是这个“缓存路径”的一部分。因此,如果您在不同的目录中有相同的源/目标(foo.c->foo.obj),它们将具有不同的“缓存路径”并且彼此独立构建。

如果您真的想在不同项目之间共享源代码,请注意 CacheDir 功能如何更适用于在不同开发人员之间共享相同的源代码,您可能需要查看 Repository() 方法。它让您可以将另一个源代码树挂载(混合)到您当前的项目中......

【讨论】:

  • (A) 如果您正确地假设 absolute 路径是构建签名的一部分,那么缓存在我的琐碎 helloworld 示例中将不起作用。尽管缓存 确实 在这种情况下有效。 (B) 我删除了目标文件,启动了scons --debug=pdbbreak SCons.Node.FS.File.get_cachedir_bsig。调试器没有停止在get_cachedir_bsig
  • 好像有一个误区:你假设项目中有两个内容相同的文件。我的情况是:项目签出两次。
  • 可能的。所以你能否在你的问题中澄清你如何检查你的来源两次,然后为 SCons 安排它,我认为它在两个副本的控制之下,它看不到两个副本,而只有一个?您的文件夹结构实际上是怎样的?如何设置您的 SConstruct?
猜你喜欢
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-08
相关资源
最近更新 更多