我们正在开发一个c++库,目前有超过500个独立的。cpp文件。它们都被编译并归档到一个静态库中。即使是并行构建,这也需要几分钟。我想减少编译时间。
每个文件平均有110行,里面有一两个函数。但是,对于每个.cpp文件都有一个相应的.h头文件,这些头文件通常包含在许多.cpp文件中。例如,A.h
可能被A.cpp
、B.cpp
、C.cpp
等所包含。
我首先要配置文件的编译过程。有没有一种方法可以知道做什么事花了多少时间?我担心打开头文件浪费了很多时间,只是为了检查包含保护而忽略文件。
如果这类事情是罪魁祸首,那么减少编译时间的最佳实践是什么?
我愿意添加新的分组头,但可能不愿意改变这种多文件布局,因为这允许我们的库也作为一个按需头的库。
真的很难。
我在工作中致力于改善我们项目的编译时间,并发现一个文件需要15分钟(在-O2
中编译时,但在-O0
中大约15秒)并且被编译两次,因此总的编译时间约为60-70分钟,这大约是一半的时间。关闭一个优化功能使一个文件缩短到大约20秒,而不是15分钟。这个文件生成了一个由机器生成的函数,它有几万行长,这导致编译器执行一些神奇的长操作(可能是某种O(N^2)算法)。
如果您有一个小函数,然后依次调用许多小函数,最终通过内联层变成一个大文件,也可能发生这种情况。
在其他时候,我发现减少文件数量并在一个文件中放入更多代码效果更好。
总的来说,我的经验(包括我自己的编译器项目,以及其他人/公司的编译器)不是解析和读取文件花费时间,而是各种优化和代码生成过程。您可以通过使用-fsyntax-only
或您的编译器调用的任何内容编译所有文件来尝试。它将读取源代码并检查其语法是否正确。如果您还没有使用-O0
,请尝试编译。通常特定的优化通道是问题所在,有些通道比其他通道更糟糕,因此检查特定-O
选项中有哪些单独的优化通道是有用的-在gcc中可以与-Q -O2 --help=optimizers
一起列出[在本例中为-O2
]。
你真的需要弄清楚编译器花时间在哪里。如果问题是您花费了大部分时间来优化代码,那么更改代码是没有意义的。如果时间花在解析上,那么减少优化器是没有意义的,而且优化不会增加额外的时间。没有实际构建你的项目,很难确定。
另一个技巧是检查top
,看看你的编译进程是否每个都使用了100%的cpu——如果不是,你的编译机器可能没有足够的内存。我的工作项目有一个构建选项,它"杀死"了我的桌面电脑,因为它运行太多内存耗尽,整个系统都陷入停顿——甚至在网络浏览器中从一个选项卡切换到另一个选项卡都需要15-30秒。唯一的解决方案是减少-j
的运行[当然,我通常会忘记,在那一点上-所以如果我不想打断它,我就去吃午饭,长时间的咖啡休息或诸如此类的直到它完成,因为机器是不可用的]。这只适用于调试构建,因为将大型代码库的调试信息放在一起会占用大量内存[显然!
如果这类事情是罪魁祸首,那么减少编译时间的最佳实践是什么?
如果你的预处理器支持#pragma once
指令,使用它。这将确保.h文件不会被读取超过一次。
如果没有,在.cpp文件中使用#include
守卫。
假设你有
A.h:
#ifndef A_H
#define A_H
...
#endif
您可以在a.p中使用以下方法:
#ifndef A_H
#include "A.h"
#endif
您需要对每个.h文件重复该模式。例如
#ifndef B_H
#include "B.h"
#endif
#ifndef C_H
#include "C.h"
#endif
#include
守卫的使用,请参阅。cpp文件中包含守卫的功能是什么?我不知道您是否已经这样做了,但是在头文件中使用前向声明而不是include应该会提高编译速度。有关更多信息,请参阅此问题:
应该尽可能使用前向声明而不是包含吗?
另一个减少编译时间的方法是使用ccache
。它缓存以前编译的结果。
https://ccache.samba.org
将您的代码结构为使用PIMPL范式。两个主要的好处是:
- 你可以隐藏所有的实现(成员变量等)从用户
- 如果你改变了你的实现文件,那么"通常"只有这个区域需要重新编译,而不是完全重建。
查看此处