【问题标题】:SCons setup for hierarchical source but single targetSCons 设置分层源但单一目标
【发布时间】:2012-01-10 20:58:28
【问题描述】:

我有一个 C++/Python 项目,我一直在从事该项目,到目前为止,我一直依赖 Visual Studio 来管理构建。现在我想自动化构建过程,希望包括多平台支持(都是标准的 C++/Python),并且认为 SCons 可能是完成这项工作的工具。

涉及的源文件很多,在多个目录中,但一个(立体)典型示例如下:

foo.lib
  directory_1
    bar1_1.cpp
    bar1_2.cpp
    ... etc. ...
  directory_2
    bar2_1.cpp
    bar2_2.cpp
    ... etc. ...

因此,换句话说,源文件处于层次结构中,但只有一个目标。 (层次结构在代码中使用的命名空间中匹配,但这对于这个问题来说是多余的。)

我的问题是:构建 SConstruct 和 SConscript 文件的最佳方式是什么?我阅读了 SCons 文档,特别是 Hierarchical Builds 部分以及使用多个 SConscript 文件和合适的“SConscript”调用的想法。一切看起来都很清晰,而且特别整洁。然而,这似乎适用于具有多个目标的层次结构。我可以在只有一个目标的情况下使用相同的功能吗?

(我确实想到了一个顶级的 SConstruct/SConscript 文件,至少对于有问题的库来说,列出了所有带有子目录的源文件,但并不是“感觉”最好的方法。也许这确实是前进的方向?)

非常感谢您提供任何建议/见解。

【问题讨论】:

    标签: c++ python build scons


    【解决方案1】:

    我曾多次使用类似于您描述的分层解决方案。我选择了这样的解决方案:

    在 SConscript 中:

    #/bar/SConscript
    Import("env")
    env = specialize_env_for_this_subpackage()
    
    myfiles = Glob(*.cpp)
    apply_any_exclusions(myfiles)
    myobjects = env.Object(myfiles)
    
    Return(myobjects)
    

    然后在 SConstruct 中:

    #SConstruct
    env = construct_general_environment()
    
    subpackages = ["foo","bar","baz"] #or perhaps call your own find_subproject() function
    
    objects = SCons.Node.NodeList
    for package in subpackages:
        pack_objects = env.SConscript(os.path.join(package,"SConscript"), exports = env)
        objects.extend(pack_objects)
    program = env.Program("myprog",objects)
    
    Default(program)
    

    然后您可以对每个包中的环境进行微调控制,并且通过巧妙地使用 *site_scons* 文件夹,您可以防止每个 sconscript 一遍又一遍地重复相同的行。这种方法的另一个优点是 scons 文件反映了设计。我也更喜欢使用 Glob 来收集 cpp 文件,允许我根据需要添加和删除文件,而无需为此类琐碎的操作编辑任何构建文件。

    【讨论】:

    • 谢谢!我今晚要试一试,我想这几乎正是我想要的。唯一突出的项目是更改特定文件的构建标志(以禁用包含 3rd 方库等生成的警告)。不过,我可以忍受这些警告......
    • 在更改环境时记得做一个深拷贝,否则更改会影响以后的包。 env.Clone() 会很好地复制环境。
    • 是的 - 好点子!当然,我立即遇到了这个:-)。您的评论证实了我哪里出错了。
    【解决方案2】:

    在一个SConstruct 文件中列出所有源文件并没有错。分层构造 SConscripts 也很好,但是您需要从每一层返回对象,这会有点傻:

    # SConscript, for example
    sources = ["bar1_1.cpp", "bar1_2.cpp", ...]
    objects = [env.Object(x) for x in sources]
    Return(objects)
    
    # SConstruct (top-level)
    directory_1_objects = SConscript("directory_1/SConscript")
    directory_2_objects = SConscript("directory_2/SConscript")
    program = env.Program("magical_wonders", [directory_1_objects, directory_2_objects])
    

    在我自己看来,特定二进制文件中所有源文件的单个顶级栅格比这更可取,因为当文件层次结构发生变化时需要更多布线。

    【讨论】:

    • 谢谢!这无疑突出了我在文档中明显跳过(或误解)的一个功能。我的请求源于我想处理的两个案例:i)选择性包含某些文件; ii) 为各个文件指定不同的构建标志。经审查,案例(i)确实是我懒惰的一个例子。现在我只是坚持使用案例(ii) - 一个示例是禁用特定文件的警告,但不会全局禁用它。 (我希望通过特定 SConscript 文件中的合适环境处理来处理这个问题。虽然我可能再次陷入困境......)
    猜你喜欢
    • 1970-01-01
    • 2014-08-05
    • 1970-01-01
    • 2022-10-30
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-23
    相关资源
    最近更新 更多