SCons 和/或 CMake:有什么方法可以自动从“编译期间包含的头文件”映射到“必须链接相应的目标文件”?

Sco*_*ies 5 build cmake scons

超级简单,完全无聊的设置:我有一个充满 .hpp 和 .cpp 文件的目录。其中一些 .cpp 文件需要构建到可执行文件中;自然,这些 .cpp 文件 #include 某些 .hpp 文件在同一目录中,然后可能包含其他文件,等等。这些 .hpp 文件中的大多数都有相应的 .cpp 文件,也就是说:如果 some_application.cpp #includes foo.hpp,无论是直接的还是传递性的,那么很可能还有一个 foo.cpp 文件需要编译并链接到 some_application 可执行文件中。

超级简单,但我仍然不知道构建它的“最佳”方式是什么,无论是在 SCons 还是 CMake(我都没有任何专业知识,除了在最后一天左右盯着文档和变得悲伤)。我担心我想要的那种解决方案实际上不可能(或至少非常复杂)在大多数构建系统中实现,但如果是这样,很高兴知道这一点,这样我就可以放弃并且不那么挑剔了. 当然,我希望我是错的,考虑到我对构建系统(一般来说,尤其是 CMake 和 SCons)一无所知,这并不奇怪。

当然,CMake 和 SCons 都可以自动检测到 some_application.cpp 需要重新编译,只要它依赖的任何头文件(直接或传递)发生变化,因为它们可以很好地“解析”C++ 文件以挑选出那些依赖关系。好的,太好了:我们不必手动列出每个 .cpp-#includes-.hpp 依赖项。但是:我们仍然需要决定在实际生成每个可执行文件时需要将哪些目标文件子集发送到链接器。

据我了解,处理这部分问题的两个最直接的替代方法是:

  • A. 手动明确且费力地枚举“任何使用此目标文件的东西也需要使用这些其他目标文件”依赖项,即使这些依赖项由相应的-.cpp-transitively-includes-the-corresponding-.hpp完全镜像构建系统已经为我们找到了麻烦。为什么?因为电脑。
  • B. 将该目录中的所有目标文件转储到一个“库”中,然后让所有可执行文件依赖并链接到该库中。这要简单得多,我理解大多数人会这样做,但它也有点草率。大多数可执行文件实际上并不需要该库中的所有内容,并且如果仅更改一两个 .cpp 文件的内容,则实际上不需要重新构建。这不正是所谓的“构建系统”应该避免的那种不必要的计算吗?(我想如果库是动态链接的,也许它们不需要重建,但足以说明我出于其他原因不喜欢动态链接的库。)

CMake 或 SCons 能否以任何远程直接的方式做得比这更好?我看到了一堆有限的方法来处理自动生成的依赖关系图,但没有通用的交互方式(“好吧,构建系统,你认为依赖关系是什么?啊。好吧,基于此,添加遵循依赖项并再次思考:...”)。我也不对此感到惊讶。不过,我还没有在任一构建系统中找到一种特殊用途的机制来处理超级常见的情况,在这种情况下,链接时依赖项应该反映相应的编译时 #include 依赖项。我在阅读文档时(诚然有些草率)错过了什么,还是每个人都选择了选项 (B) 并悄悄地讨厌自己和/或他们的构建系统?

Bra*_*ady 2

您在 A 点中的陈述“使用此目标文件的任何内容也需要使用这些其他目标文件”确实需要手动完成。编译器不会自动查找二进制文件所需的目标文件。您必须在链接时明确列出它们。如果我正确理解您的问题,您不想显式列出二进制文件所需的对象,而是希望构建工具自动找到它们。我怀疑是否有任何构建也可以做到这一点:SCons 和 Cmake 绝对不会这样做。

如果您有一个some_application.cpp包含foo.hpp(或这些 cpp 文件使用的其他标头)的应用程序,并且随后需要链接该foo.cpp对象,那么在 SCons 中,您将需要执行如下操作:

env = Environment()
env.Program(target = 'some_application',
            source = ['some_application.cpp', 'foo.cpp'])
Run Code Online (Sandbox Code Playgroud)

当“some_application.cpp”、“foo.hpp”或“foo.cpp”发生更改时才会链接。假设使用 g++,这将有效地转换为如下内容,独立于 SCons 或 Cmake。

g++ -c foo.cpp -o foo.o
g++ some_application.cpp foo.o -o some_application
Run Code Online (Sandbox Code Playgroud)

您提到您有“一个充满 .hpp 和 .cpp 文件的目录”,我建议您将这些文件组织到库中。并非全部集中在一个库中,而是按逻辑将它们组织成更小的、有凝聚力的库。然后您的应用程序/二进制文件将链接它们所需的库,从而最大限度地减少由于未使用的对象而导致的重新编译。