1
learningman 2023-02-14 14:18:29 +08:00 1
"头文件会很重复包含多次,编译器每次都会解析一遍,就会很慢"
#pragma once #ifundef AAA #def AAA #endif |
2
msg7086 2023-02-14 14:19:43 +08:00
换一个不会每次都会解析一遍的编译器?
|
3
AllenTsui 2023-02-14 14:20:41 +08:00
可读性 >>> 运行性能 >>> 编译性能
|
4
yanqiyu 2023-02-14 14:21:38 +08:00 via Android
https://en.cppreference.com/w/cpp/language/modules
@learningman OP 指的应该是不同翻译单元都用到的头文件解析耗时,比如 STL 里面模板库的展开,每个翻译单元都要一次 没啥好方法,要么做一些结构性的更改,要么就用 C++20 的现在编译工具链支持不是很好的 modulws |
5
codehz 2023-02-14 14:22:20 +08:00 via iPhone
不可以并行化吗
然后如果源文件没变的话,不可以直接用缓存的结果吗 然后,还有 pch 和 c++模块系统呢 |
6
ysc3839 2023-02-14 14:22:49 +08:00 via Android
实际开发时基本都会开启预编译头,拆分成多个 cpp 是更快的,而且拆分的话改了其中一个 cpp 后只需要重新编译这个 cpp 即可,不需要全部重新编译,也会快很多。
|
7
cnbatch 2023-02-14 14:23:14 +08:00
长久以来的做法是,使用 Precompiled Header (预编译头)功能
如果用上了 C++20 ,可以尝试下 Modules |
8
tool2d OP |
9
acctv2 2023-02-14 14:24:21 +08:00 via Android
没有具体实践过,理论上一大堆小文件链接时间会更长,所以有可能。
头文件一遍遍解析? ifndef 不行吗 |
10
tool2d OP @ysc3839 感觉预编译头也不是万能的,我看很多开源 linux 项目很少用到预编译头。
因为这意味着你写 C++代码,不能直接去 include 指定的 fileA.h 和 fileB.h 。必须 include stdafx.h ,其中 stdafx.h 又包含了 fileA.h 和 fileB.h 。 最后用起来也没那么直观。只能说是 trade off 。 |
11
DIMOJANG 2023-02-14 14:33:05 +08:00
是的,方法可以平衡编译速度和源文件的合理划分。
一种方法是使用预编译的头文件,它允许你预编译常用的头文件,减少每个包含它们的 CPP 文件的解析时间。 另一种方法是使用模块,这是 C++中一个较新的功能,允许你编译和链接较小的代码单元。 此外,你可以将你的源文件组织成逻辑模块或命名空间,以更好地反映你的代码结构,减少不必要的头文件的包含。 |
12
tool2d OP 说说我自己的解决办法,就是用.inl (INLINE)文件写代码,IDE 不会编译,只需要在 CPP 里包含.inl 就可以了。
一个 CPP 是单独的模块,模块里的子功能,全部都在分散在若干个.inl 文件里。 但是感觉就我一个人这样规划代码结构,有那么一点奇葩。 |
13
codehz 2023-02-14 14:56:47 +08:00 via iPhone
@tool2d stdafx 只是一个约定,实践中只要构建系统支持,你可以任意指定某个头文件生成 pch ,并不是一个项目只能有一个 pch
|
14
tool2d OP |
15
lixile 2023-02-14 15:11:19 +08:00
? 实践中 常用场景不是增量编译次数远大于 全量编译场景吗
主流的构建系统(指代我熟悉的 linux 体系下的 makefile cmake 等)应该都支持增量编译才对 那明显是多 cpp 更合适吧速度更快 否则单个巨无霸 往往只能使用一个 cpu 核心进行编译 完全没办法并行编译。 |
16
ligiggy 2023-02-14 15:18:27 +08:00
@tool2d #12 ,你说的就是用纯使用 内联函数,很显然这个方法不通用。把一个又一个的大函数,分解成一个又一个的 内联函数,理想很美好,现实很骨感。
其次,你的 inl 文件或者说头文件,有这么多的内联实现,不就暴露了大部分接口。 然后在针对每个类的成员函数,你把一个函数,在多个文件里面实现,是不是也要每个文件定义成类的一部分,编译的时候也很复杂啊,或者你在函数里面将类型当成参数,写着写着就丢失了 C++的灵魂。 |
17
tool2d OP @ligiggy 我用的.inl ,没用到 INLINE 关键字,就只是当成普通的 CPP 源文件使用。
和普通 CPP 的唯一区别,是.cpp 后缀 IDE 会自动编译成 obj ,而.inl 后缀 IDE 会选择忽视。 可能和官方有冲突,我也想不出别的扩展名了。 |
18
Nazz 2023-02-14 15:33:30 +08:00
很符合直觉, 只是这样不方便维护.
|
19
Shuenhoy 2023-02-14 15:35:40 +08:00
https://cmake.org/cmake/help/latest/prop_tgt/UNITY_BUILD.html
各种构建工具有一种被称为 unity build 的功能,可以自动帮你把一些小文件合并。 不过需要注意,这种情况下比一堆小文件快只是对从 0 编译而言的,如果你需要一边改一边编译,可能还是分多个编译单元更快。 当然,整这些其实都没啥用,正解还是 C++20 的 module ( |
20
yolee599 2023-02-14 15:40:10 +08:00
并不反直觉。多个文件需要经历预编译,把文件都整合到一起,编译出来的中间文件还要链接到一起组成可执行文件,当然比单独一个文件慢了。
|
21
kidonng 2023-02-14 15:40:36 +08:00 2
一看到标题就想到 sqlite https://opensource.apple.com/source/CPANInternal/CPANInternal-108/DBD-SQLite/sqlite3.c.auto.html
** This file is an amalgamation of many separate C source files from SQLite ** version 3.6.22. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a one translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements ** of 5% are more are commonly seen when SQLite is compiled as a single ** translation unit. 虽然说的是运行速度不是编译速度🐶 |
22
tyrantZhao 2023-02-14 15:42:06 +08:00
可读性大于编译速度,都用 cpp 了,就别考虑编译速度了。
|
23
kemchenj 2023-02-14 16:08:02 +08:00 1
前面的人说了很多了,其实主要就是并发编译多个文件,头文件重复解析导致的,而且还得竞争写入编译缓存,结果就是所有线程都在互等。
LLVM 大会还有一个 Session 专门讲这件事情 ,感兴趣的话可以看一下。 |
24
debuggerx 2023-02-14 16:20:41 +08:00
|
25
nullyouraise 2023-02-14 17:52:31 +08:00 via iPhone
很多大型项目的构建系统都有这种机制,Unity 、Unreal 等,build 之前会按照一定规则将源文件通过 include 来放入一个更大的 cpp 中一次性编译
Chromium 曾经也有这种机制叫 Jumbo Build ,但开发团队认为由此获取的编译速度提升与带来的各种编译错误问题相比收益太小,在 2018 年左右时取消了,导致当时我编译耗时翻了四倍 |
26
antonius 2023-02-14 18:06:00 +08:00
上面都说了可读性>编译速度,提高编译速度可以试试 ninja + buildcache + icecream
|
27
tool2d OP @antonius 倒不是说写新代码都要一个主文件,而是我最近看的几个古老 CPP 项目代码,很多都是一个文件有 1 万行。
我就在思考,IDE 有没有很科学的办法,去管理一个巨大代码文件。并让人舒服在里面写代码,和按照功能跳来跳去。 |
28
GordianZ MOD @tool2d 我二十多万行的 CPP 文件 VS 打开补全啊啥的完全不能用。只要一按 F12 跳转 IntelliSense 就崩溃,全是红波浪。我都是单独开别的编辑器搜索函数名来用……
|
29
icylogic 2023-02-14 18:32:48 +08:00 1
可以参考 cotire ,主要干的事就是
- precompiled header 预编译头,但是只能解决一部分 - single compilation unit ( cmake 的 unity build )把 cpp 整合成一个巨大的编译单元 c 艹 加速编译还有一大堆可以做的事,比如 ccache ,distcc ,pimpl … |
30
kkocdko 2023-02-15 00:33:37 +08:00 via Android
是的
jumbo_build |
31
litguy 2023-02-15 08:18:03 +08:00
@GordianZ 50W 行 C++ 路过,绝大部分是 .hpp 的模板类,编译起来有点慢( x86 还行,国产 ARM 即使 make -j64 也及其慢),但是 vs code 打开还是很顺利,平常都是 ssh remote 方式开发,符号跳转有时候不怎么好用,从来没用过补全功能,单纯打字写代码,感觉还很流畅
|
32
tool2d OP |