SCons在层次源下的单一目标设置

5 投票
2 回答
2701 浏览
提问于 2025-04-17 09:57

我正在做一个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的文档,特别是关于层级构建的部分,了解到可以使用多个SConscript文件,并适当地调用'SConscript'。这一切看起来都很清晰,也很整洁。不过,这似乎是为有多个目标的层级结构设计的。我能否在只有一个目标的情况下使用这个功能?

(我确实考虑过为这个库创建一个顶层的SConstruct/SConscript文件,列出所有的源文件和子目录,但这样做似乎不太“合适”。也许这确实是前进的方向?)

非常感谢任何建议或见解。

2 个回答

5

我之前多次使用过一种类似你描述的分层解决方案。我选择了这样的解决方案:

在 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 文件,这样我可以随意添加或删除文件,而不需要为了这些小操作去修改任何构建文件。

0

在一个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])

我个人认为,把特定二进制文件的所有源文件放在一个顶层的列表中,比起这种分层结构要更好,因为当文件层次结构发生变化时,这样的做法需要的调整会更多。

撰写回答