如何使用多个使用存储库的 SConstruct 文件从树中的不同位置进行构建?

How do I build from different locations in my tree with multiple SConstruct files that use Repositories?

我有以下目录结构:

root/
  SConstruct
  item0/
    SConstruct
    unit0/
      unit0.h
      private/
        unit0.c
      test/
        test_unit0.c
        SConstruct
        SConscript
    unit1/
      (repeat unit0 structure)
  item1/
    (repeat item0 structure)

我希望能够 运行 从 root scons 构建它下面的所有东西,从 root/item0 构建它下面的所有东西,等等

顶级 SConstruct 如下所示:

SConscript('item0/SConstruct', duplicate=0)
SConscript('item1/SConstruct', duplicate=0)

项目级 SConstruct:

SConscript('unit0/SConstruct', duplicate=0)
SConscript('unit1/SConstruct', duplicate=0)

单元级SConstruct:

import os

proj_root = os.path.abspath('../../../../..')
proj_shared_path = os.path.join(proj_root,
    os.path.normpath('trunk/sys/shared'))

env = Environment()
SConscript(
    'SConscript',
    variant_dir='output',
    exports=['env', 'proj_shared_path'],
    duplicate=0)

单位级 SConscript(仅重要内容):

Import('*')
# Setup Repositories to access out-of-current-directory-tree files.
lib1_path = os.path.join(proj_shared_path, 'lib1')
env.Repository('#/../private', lib1_path)

# Set general compilation and link flags.
env.Append(
    CFLAGS = '-Wall -Wextra -std=c99 -pedantic',
    CPPPATH = ['#/../..', proj_shared_path])

# These are the files we don't need to run gcovr on.
non_cov_srcs = [
    'testit.c',
    'lib1.c'
    ]

# Create a 'coverage' environment to build files that we will run gcovr on.
cov = env.Clone()
cov.Append(CFLAGS = '--coverage -O0')
cov_srcs = cov.Object('unit0.c')
SideEffect('unit0.gcno', cov_srcs)

# Our unit test program combines all the sources we've listed so far.
test_exe = env.Program(
    'test_unit0',
    [cov_srcs, non_cov_srcs],
    LIBS='gcov', LINKFLAGS='--coverage')

现在,当我 运行 从 root/item0/unit0/test scons 时,一切正常。但是,当我从 rootroot/item0 运行 时,我会收到各种类型的错误,如下所示 (运行 from root/item0):

scons: done reading SConscript files.
scons: Building targets ...
scons: *** [unit0\test\output\unit0.obj] Source 'unit0\test\unit0.c' not found, needed by target 'unit0\test\output\unit0.obj'.
scons: building terminated because of errors.

显然 unit0\test\unit0.c 不会被发现,因为它不存在,但我不确定为什么 scons 认为它​​必须存在,因为存储库被定义为 '#/../private' 并且在那里错误消息中没有显示私人。

edit 我发现它可能在寻找 unit0\test\unit0.c 因为 unit0\test 是 [=26= 的 "root" 目录].我还猜测 #/../private Repository 位置只有在 sconsunit0\test 的 运行 时才是正确的。但是,当我尝试以任何其他方式指定 Repository 时(包括使用 os.path.abspath 构建的绝对路径(并验证为正确)),scons 似乎仍然不想要在那里寻找 unit0.c。这是为什么?

在#scons IRC 频道@bdbaddog 的进一步帮助下,我能够确定以下内容:

  1. 我实际上想要实现的是确保每个源的构建工件最终都在我的 variant_dir
  2. 由于 SConstructSConscript 在同一目录中,Repository 在从 unit0/test 目录构建时最终实现了这一点。但是,我不知道为什么。

要正确实现 (1),Repository 不是正确的工具。相反,SConscript 应该是这样的:

Import('*')

# Set general compilation and link flags.
env.Append(
    CFLAGS = '-Wall -Wextra -std=c99 -pedantic',
    CPPPATH = ['#/item0', '#/lib1'])

# These are the files we don't need to run gcovr on.
non_cov_objs = [
    Object(target='testit', source='testit.c'),
    Object(target='lib1', source='#/lib1/lib1.c'
    ]

# Create a 'coverage' environment to build files that we will run gcovr on.
cov = env.Clone()
cov.Append(CFLAGS = '--coverage -O0')
cov_objs = cov.Object(
    target='unit0', 
    source='#/item0/unit0/private/unit0.c')
SideEffect('unit0.gcno', cov_srcs)

# Our unit test program combines all the sources we've listed so far.
test_exe = env.Program(
    'test_unit0',
    [cov_objs, non_cov_objs],
    LIBS='gcov', LINKFLAGS='--coverage')

通过为每个 Object 指定 targetsource,我可以根据在 variant_dir.