构建 – SCons和/或CMake:从“编译时包含的头”到“相应的目标文件必须链接”的任何方式自动映射?

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

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

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

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

> A.明确且费力地枚举“使用此目标文件的任何东西也需要手动使用这些其他目标文件”依赖性,即使这些依赖项完全由相应的-cpp-transitively-includes-the-对映射.构建系统已经陷入困境的hpp依赖关系为我们搞清楚了.为什么?因为电脑.
> B.将此目录中的所有目标文件转储到单个“库”中,然后让所有可执行文件依赖并链接到该库中.这更简单,我理解大多数人会这样做,但它也有点草率.大多数可执行文件实际上并不需要该库中的所有内容,如果只更改了一个或两个.cpp文件的内容,则实际上不需要重建.这不是设置所谓的“构建系统”应该避免的那种不必要的计算吗? (我想如果库是动态链接的话,也许不需要重建它们,但是说我不喜欢动态链接库的其他原因.)

CMake或SCons可以以任何远程直接的方式做得比这更好吗?我看到了一些有限的方法来改变自动生成的依赖图,但没有通用的方式来交互式地执行(“好的,构建系统,您认为依赖是什么?啊.好吧,基于此,添加遵循依赖关系并再次思考:……“).我对此并不感到惊讶.我还没有在构建系统中找到一个特殊用途的机制来处理超常见的情况,其中链接时依赖性应该反映相应的编译时#include依赖性.我是否遗漏了我的(粗略地有点粗略)阅读文档,或者每个人都选择(B)并且悄悄地讨厌自己和/或他们的构建系统?

最佳答案
你在A)中的陈述“任何使用这个目标文件的东西都需要使用这些其他目标文件”,这确实需要手工完成.编译器不会自动查找二进制文件所需的目标文件.您必须在链接时明确列出它们.如果我正确理解您的问题,您不希望必须明确列出二进制文件所需的对象,但希望构建工具自动找到它们.我怀疑是否有任何构建这样做:SCons和Cmake肯定不会这样做.

如果你有一个包含foo.hpp的应用程序some_application.cpp(或这些cpp文件使用的其他头文件),然后需要链接foo.cpp对象,那么在SCons中,你需要做这样的事情:

env = Environment()
env.Program(target = 'some_application',
            source = ['some_application.cpp', 'foo.cpp'])

这只会在’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

你提到你有一个“.hpp和.cpp文件的目录”,我建议你把这些文件整理成库.不是所有的都在一个库中,而是在逻辑上将它们组织成更小,更有凝聚力的库.然后,您的应用程序/二进制文件将链接所需的库,从而最大限度地减少因未使用的对象而导致的重新编译.

转载注明原文:构建 – SCons和/或CMake:从“编译时包含的头”到“相应的目标文件必须链接”的任何方式自动映射? - 代码日志