makefile - 与旧版本相比,CMake 3.16 在 Makefile 的生成阶段慢了几个数量级

标签 makefile cmake strace callgrind

我正在咨询一家公司如何加快他们的构建速度,我立即向他们指出了预编译 header 和统一构建 - 10 分钟的完整构建可以轻松缩短到 2-3 分钟。幸运的是 CMake 3.16 最近发布了 it supports both of those ,所以我告诉他们升级。

问题如下:从 CMake 2.6 切换到 3.16 后,运行 CMake 所需的时间从大约 20 秒跃升至 10 多分钟。大部分时间都花在生成阶段。如果您给它足够的时间并且使用 Unity 构建成功编译了代码,它确实会成功完成,但这个 CMake 时间是 Not Acceptable 。

这是他们的设置:

  • CMake 2.6,带有全局标志/定义/包含的旧式 CMake - 不是现代的(基于目标)。没有什么太花哨的 - 没有自定义命令或构建规则和复杂的依赖关系。
  • 使用的编译器是 GCC 7,生成 Makefile - 操作系统是 CentOS 7,内核:Linux 3.10.0-862.14.4.el7.x86_64
  • 大约 2000 个 .cpp 文件分布在 100 个库和 600 个可执行文件中(其中大部分是测试可执行文件,其中包含一个 .cpp)
  • 大多数 .cpp 文件都是用 aux_source_directory 收集/通配的- 我们知道不明确列出 .cpp 文件是一种反模式,但这不是重点 - 我认为这是无关紧要的,因为这应该发生在配置步骤中而不是生成期间,对吗?

以下是我们观察到的情况:

  • 我们对不同的 CMake 版本进行了二进制搜索,得出的结论是,巨大的减速发生在 3.15 和 3.16 之间 - 正是在添加预编译头和统一构建支持的时候,但我认为这些功能与速度放缓 - 我想不出它们产生如此影响的原因 - 一定是其他一些重构或改变......
  • 我们禁用了所有测试(这意味着几乎所有 600 个可执行文件都被删除) - 将 CMake 目标的数量从 700 个减少到 100 个以上 - 运行 CMake 所需的时间显着下降,但仍然是几个对于所有 700 个目标,比使用 CMake 2.6 的时间长 1 倍。
  • 我们使用 strace 观察了发生的情况,主要是 lstataccess 调用以及一些读取和写入 - 但这是无止境的- 看起来每秒有数百次操作,以非常可重复的方式进行。此外,还不断尝试查找 libgflags.so ,但始终失败。不幸的是我现在没有这样的日志。
  • 我们创建了一个 callgrind 配置文件,运行几分钟后如下所示:/image/tEqaF.png (可以找到 callgrind 输出文件 here ) - 似乎大部分时间都花在 ComputeLinkLibs() 上并获取目标的全名和定义等等......有 700 个目标太多了?这是一个指数问题吗?为什么 CMake 3.15 没有问题?

我在互联网上找不到任何其他人遇到同样问题的报告...有什么想法下一步要尝试吗?也许使用 Perf 进行配置?尝试使用 Ninja 作为后端 ( report of that being faster )?

最佳答案

分析得很好。这对于 CMake 的开发人员会有帮助。但我怀疑你会在这里找到很多帮助。请开通issue .

如果您能提供一个最小的示例来展示您的问题,则可获得奖励积分。您可能会通过生成大量文件来得到这个。

关于makefile - 与旧版本相比,CMake 3.16 在 Makefile 的生成阶段慢了几个数量级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60093679/

相关文章:

linux - 通过系统调用监控Linux上的内存

C语言,如何包含从 "XXX.h"到<XXX.h>的文件”,也许使用Makefile?

c++ - 在 makefile 之外运行应用程序时出现段错误

python - 从 python 包安装脚本中安装 CMake 宏脚本(使用 setup.py)

linux - 为什么 strace 的 -c 和 -T 时间不一致?

debugging - 查看/拦截所有 emacs lisp 函数调用

android - 包括库在Android项目中使用的共享对象

makefile - 非递归 makefile 示例

c++ - 在 Windows `Can' t 打开包含文件时设置 CMake 和 vcpkg 时出错

c++ - 使用不同的预处理器宏从同一源代码树构建多个目标