Skip to content

Commit 094ba1b

Browse files
committed
增加c++三方库编译优化
增加c++三方库编译优化
1 parent ce8e8b4 commit 094ba1b

File tree

2 files changed

+158
-31
lines changed

2 files changed

+158
-31
lines changed

_posts/2023-10-08-chatgpt4如何提高了程序员的工作效率.md

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
---
2+
title: c++ 三方库如何编译优化
3+
date: 2024-08-24 18:18:18 +0800
4+
categories: c++
5+
tags:
6+
---
7+
8+
`spdlog``nlohmann/json`这样的仅标头(header-only)库因其易用性和便捷性而广受欢迎,但它们在大型项目中可能会带来编译时间和生成文件体积膨胀的问题。以下是针对这些库的优化策略:
9+
10+
### 1. **分离编译(Explicit Template Instantiation)**
11+
12+
对于像`nlohmann/json`这样的模板库,编译时间和二进制体积膨胀的问题可以通过显式实例化模板来缓解。
13+
14+
**nlohmann/json分离编译示例**:
15+
1. **声明模板类(头文件)**:
16+
```cpp
17+
// json_wrapper.h
18+
#include <nlohmann/json.hpp>
19+
20+
class JsonWrapper {
21+
public:
22+
using json = nlohmann::json;
23+
static json parse(const std::string& data);
24+
};
25+
```
26+
27+
2. **定义模板类(源文件)**:
28+
```cpp
29+
// json_wrapper.cpp
30+
#include "json_wrapper.h"
31+
32+
nlohmann::json JsonWrapper::parse(const std::string& data) {
33+
return nlohmann::json::parse(data);
34+
}
35+
36+
// Explicit template instantiation for common types
37+
template nlohmann::json JsonWrapper::parse<int>(const std::string&);
38+
template nlohmann::json JsonWrapper::parse<double>(const std::string&);
39+
```
40+
41+
通过将常用的模板实例化放在一个实现文件中,你可以减少头文件的编译开销,并减少重复代码的实例化。
42+
43+
### 2. **减少包含头文件的范围**
44+
45+
**使用前置声明**: 尽量减少头文件的包含范围。在不需要完整定义的情况下,使用前置声明。
46+
47+
**spdlog使用前置声明示例**:
48+
```cpp
49+
// 只需要指针或引用的地方使用前置声明
50+
namespace spdlog {
51+
class logger;
52+
}
53+
54+
void log_message(spdlog::logger* logger, const std::string& message);
55+
```
56+
57+
在实现文件中再包含`spdlog`的头文件:
58+
```cpp
59+
#include <spdlog/spdlog.h>
60+
61+
void log_message(spdlog::logger* logger, const std::string& message) {
62+
logger->info(message);
63+
}
64+
```
65+
66+
### 3. **使用预编译头文件(Precompiled Headers, PCH)**
67+
68+
`spdlog``nlohmann/json`等库的头文件放入预编译头文件中,可以大大减少它们在多个文件中重复编译的时间。
69+
70+
```cpp
71+
// pch.h
72+
#include <spdlog/spdlog.h>
73+
#include <nlohmann/json.hpp>
74+
```
75+
76+
然后在编译器中设置使用预编译头文件:
77+
78+
```bash
79+
# GCC/Clang
80+
g++ -o myapp myapp.cpp -include pch.h
81+
82+
# MSVC
83+
cl /Yu"pch.h" myapp.cpp
84+
```
85+
86+
### 4. **优化头文件内容**
87+
88+
**减少不必要的头文件包含**: 在头文件中,只包含必须的内容,将所有非必要的包含放到实现文件中。
89+
90+
```cpp
91+
// Avoid including full headers
92+
class JsonWrapper; // Forward declaration
93+
94+
void process_json(const JsonWrapper& json);
95+
```
96+
97+
### 5. **模块化编译(C++20 Modules)**
98+
99+
C++20的模块可以显著减少编译时间和二进制体积。虽然`spdlog`和`nlohmann/json`目前可能没有完全支持C++20模块,但你可以自己尝试将它们封装成模块。
100+
101+
```cpp
102+
// json_module.cpp
103+
module; // global module fragment
104+
#include <nlohmann/json.hpp>
105+
106+
export module json_module;
107+
export using json = nlohmann::json;
108+
```
109+
110+
然后你可以在其他地方直接导入这个模块。
111+
112+
```cpp
113+
import json_module;
114+
115+
json j = json::parse(R"({"key": "value"})");
116+
```
117+
118+
### 6. **条件编译和宏优化**
119+
120+
在项目中使用条件编译来包含不同的功能模块,避免引入不必要的代码。
121+
122+
```cpp
123+
// config.h
124+
#define USE_SPDLOG
125+
#define USE_JSON
126+
```
127+
128+
```cpp
129+
// logger.cpp
130+
#ifdef USE_SPDLOG
131+
#include <spdlog/spdlog.h>
132+
#endif
133+
134+
void log_message(const std::string& message) {
135+
#ifdef USE_SPDLOG
136+
spdlog::info(message);
137+
#endif
138+
}
139+
```
140+
141+
### 7. **使用工具进行分析和优化**
142+
143+
- **编译时间分析**: 使用GCC的`-ftime-report`或Clang的`-ftime-trace`来分析编译时间,找出编译时间长的部分,进行有针对性的优化。
144+
- **二进制体积分析**: 使用工具如`Bloaty McBloatface`来分析生成的二进制文件,找出导致体积膨胀的部分。
145+
146+
### 8. **链接时优化**
147+
148+
使用编译器链接时优化(Link Time Optimization, LTO)来减少二进制文件大小和运行时性能开销。
149+
150+
```bash
151+
# GCC/Clang
152+
g++ -flto -o myapp myapp.cpp
153+
```
154+
155+
### 总结
156+
157+
通过分离编译、前置声明、预编译头文件、模块化编译、条件编译和使用工具进行分析和优化,你可以有效地解决仅标头库带来的编译时间和二进制体积膨胀问题。这些技术可以帮助你在保持开发效率的同时,优化项目的性能和资源利用率。
158+

0 commit comments

Comments
 (0)