gpt4 book ai didi

c++ - 单独的编译单元与单个编译单元相比,可以更快地编译,链接和优化代码?

转载 作者:行者123 更新时间:2023-12-02 13:35:40 24 4
gpt4 key购买 nike

有几个问题在讨论为什么我们应该有单独的编译单元以缩短编译时间(例如,在hpp文件中不包括任何代码,而仅在cpp文件中不包括任何代码)。

但是后来我发现了这个问题:

#include all .cpp files into a single compilation unit?

如果我们可以忽略可维护性的问题,或者只看编译/链接时间以及优化代码,那么只拥有一个hpp和cpp文件的好处和陷阱是什么?

请注意,我链接到的帖子仅讨论单个cpp文件(尽管有许多头文件)。我问如果我们只有一个hpp文件和一个cpp文件会发生什么.....

编辑:如果我们可以忽略更改单行会导致整个代码重新编译的事实,它仍然比从头开始重新编译1000个单独文件的速度还要快...

编辑:我对有关可维护性的讨论不感兴趣。我试图了解是什么使编译器更快地编译。这个问题与实际操作无关,而与仅仅了解一个简单的问题有关:

与使用单个内核将代码拆分成多个hpp和cpp文件的情况相比,将使一个大的hpp&cpp文件的编译速度更快。

编辑:我认为人们已经陷入困境,谈论什么是实用的,应该做什么。这个问题不是关于一个人应该做什么—只是为了帮助我了解编译器在做什么—直到现在还没有人回答这个问题,而是在谈论它是否可行。

编辑:除了一个实际上试图回答这个问题的人之外-我觉得这个问题没有得到应有的公正,因此被不必要地否决了。 SO是关于共享信息,而不是惩罚问题,因为提出询问的人还不知道答案。

最佳答案

它是特定于编译器的,并且取决于您从编译器询问的optimizations

最新的free software C++ 11(或C++ 14)编译器能够进行链接时优化:最近的GCCClang/LLVM都接受-flto标志(对于l墨迹t ime o刺激...)。要使用它,您应该编译并链接您的代码以及一些其他(相同)优化标志。通过make构建器的典型用法是:

make 'CXX=g++ -flto -O2' 

或者,在单独的命令中:
g++ -flto -O2 -Wall -I/usr/local/include -c src1.cc
g++ -flto -O2 -Wall -I/usr/local/include -c src2.cc
g++ -flto -O2 -Wall src1.o src2.o -L/usr/local/lib -lsome -o binprog

在链接时不要忘记 -flto -O2!

然后,将代码编译几乎与将所有 src1.ccsrc2.cc放在同一编译单元中一样。特别是,编译器能够(有时会)内联从 src1.cc中的函数到 src2.cc中的函数的调用
-flto(使用GCC,但在原则上与Clang相似)在幕后发生的事情是,编译器在每个目标文件中放置了源代码的某种中间表示形式(以Gimple/SSA形式)。在“链接时”(实际上也由编译器完成,而不仅仅是链接器完成)
对于整个程序,将重新加载,处理和重新编译此中间表示形式。因此,编译时间几乎翻了一番。

因此, -flto减慢了编译速度(大约2倍),有时可能会提高百分之几的性能(生成的二进制文件的执行时间)。因此,我几乎从不使用它。

I'm trying to understand what makes a compiler compile faster.



这是特定于编译器的,并且在很大程度上取决于您所要求的优化。通过实际和经验方法,使用最新的 GCC5GCC6g++ -O2(以及IIRC也使用 clang++ -O2),编译时间不仅与编译单元的总大小成正比(例如, token 数量或生成后的 AST的大小/数量)预处理&包括&宏扩展,甚至模板扩展),但也要扩展到最大功能的大小的平方。可能的解释与 register allocationinstruction scheduling的时间复杂度有关。请注意,C++ 11或C++ 14容器的标准 header 已扩展为相当大的内容(例如 #include <vector>提供约一万行)。顺便说一句,使用 g++ -O0进行编译比使用 g++ -O1进行编译要快于 g++ -O2。询问调试信息(例如 g++ -g2)会减慢编译器的速度。因此, g++ -O1 -g2是比 g++ -O0慢的编译器(它将产生较慢的可执行文件)。

Precompiled headers可能有助于减少编译时间(但并非总是如此!)。您将有一个通用的 header ,并且最好不要有太小的编译单元:使用20个约两千行的 *.cc文件的总编译时间要比使用200个每两百行的 *.cc文件的总编译时间稍快(尤其是因为 header 文件扩展为许多 token )。我通常建议,如果可能的话,每个 *.cc文件至少要有1000行,因此,就每个 class实现而言,只有一个小文件,每百行需要100行。对于一个微小的项目,例如具有单个源文件的4KLOC非常明智。

还要注意,C++模板的扩展非常“语法上”地进行(C++中还没有模块; Ocaml模块和函子在这方面要好得多)。换句话说, vector<map<string,long>>被“扩展”了(并且编译时很费时...),就好像在第一次出现 <vector>时插入了 <map<string>vector<map<string,long>>标准头文件一样。 AST s。因此, vector<map<string,set<long>>>第一次出现就需要大量的编译器工作,而对于“相似”的 vector<map<string,set<double>>>则必须完成几乎相同的工作量

当然,可以并行地编译几个编译单元,例如。与 make -j
要了解给定的GCC编译在哪里传递编译器时间,请将 -ftime-report传递给 g++,请参阅 this。要担心内部GCC表示的复杂性,请尝试 -fdump-tree-all一次。

为了加快整体编译时间(重点是使用 GCC的Linux系统;但是您可以根据系统调整我的答案):
  • 具有一个并行构建(例如make -j将并行运行多个g++进程,例如,每个translation unit例如每个*.cc文件一个)。学习编写足够好的Makefile -s。
  • 考虑使用一个通用的头文件和pre-compile your header(但是这可能会减慢编译时间,您需要进行基准测试);如果您保留多个头文件(这样做有很多充分的理由),请避免包含太多的小头文件,而宁愿使用更少但更大的头文件。单个将近一万行的通用预编译头文件并不罕见(您可以使用#include其中的其他几个文件)。
  • 考虑使用较大的源文件,例如有20个2000行的源文件可能比200个200行的源文件要快(因为有许多小源文件,预处理和模板扩展要重复很多),有时我确实有近一万行的源文件。但是,您通常会进行增量构建(然后可能是错误的,YMMV,您需要进行基准测试)
  • 禁用优化或降低优化级别,因此请使用g++ -O0g++ -O1而不是g++ -O2进行编译,并避免使用-flto。在许多(但不是全部)情况下,带有或不带有g++ -O3 ...的-flto都不值得付出努力(编译速度较慢,但​​是生成的机器代码并不比g++ -O2明显快得多)。但是YMMV。一些数值计算从-O3中受益匪浅。您可以考虑使用特定于函数的pragmasattributes在同一*.cc源文件中比其他函数更优化某些函数。
  • 禁用调试信息或降低调试信息,因此使用g++ -O1而不是g++ -01 -g2进行编译;但是更高的调试信息(例如g++ -g3)对于gdb调试器非常有用,因此对于YMMV来说非常有用。
  • 您可以禁用警告,但这并不值得。相反,请始终启用所有功能,因此至少将-Wall更改为g++,甚至还可能启用-Wextra,并确保您的代码在没有警告的情况下进行编译。
  • 避免使用过多的嵌套模板,例如std::set<std::vector<std::map<std::string,long>>>;在某些情况下,使用opaque pointers并使用PIMPL idiom可能会有所帮助。然后,您可能只在某些*.cc中包含一些额外的头文件(例如containers),而不是全部(但与预编译头文件不兼容,因此YMMV)。

  • 一些编译器或版本比其他编译器或版本稍快。因此,您可能更喜欢 clang++而不是 g++。我确实建议使用多个编译器(启用警告)。在您的代码中怕 undefined behavior

    请注意,C++与Java不同:您可以并且经常应该在每个文件中包含多个类或函数。再次是YMMV。

    PS。请参阅 starynkevitch.net/Basile/gcc-melt(幻灯片和文档,并点击许多链接),以获取有关GCC内部的更多信息。我在2018年放弃了GCC MELT,但幻灯片仍然有用。

    关于c++ - 单独的编译单元与单个编译单元相比,可以更快地编译,链接和优化代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39443261/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com