如何减少模板繁重的C++代码的输出大小
How to reduce output size of template-heavy C++ code?
我遇到了一个大问题。我有一个通用库,在我的整个项目中都在使用。该库集中使用boost.spirit
和boost.fusion
。不幸的是,该库的大小约为700Mb。所有的boost.spirit
重代码都被使用了,并且运行良好。可以采取哪些步骤来减少其输出大小?有没有一种工具可以帮助确定哪些模板实例化浪费了大部分空间?
起初,我决定将所有意识到精神的代码移到cpp文件中。其次,我将尝试不同的编译器标志来优化大小。我不知道还能做什么。
更新(详细信息)
我使用的是GNU工具链。巨大的图书馆实际上是一个静态图书馆。使用这个700Mb库的可执行文件大小为200Mb。至少有一半的代码在*.h文件中。一些boost.spirit
语法(非常重模板的东西)也位于*.h文件中。
干杯!
将spirit-aware代码移动到.cpp
文件是一个很好的第一步,尽管您提到在头文件中有spirit语法,但这可能是不完整的。
-
确保任何语法/规则都不会导出到库外。如果您有典型的
include
/src
目录,那么在src
目录中移动这些文件(即使是头文件)。 -
将所有这些符号标记为库内部符号。他们根本不应该从图书馆外进入。根据编译器的不同,有特定的杂注/属性,在gcc查找可见性属性时:
__attribute__ ((visibility ("internal")))
。这有助于编译器相应地优化它们,特别是编译器可能会发出函数的代码,即使它在给定的调用位置内联函数,以防该函数地址被占用。然而,在内部可见性的情况下,由于它知道代码不会离开对象,因此可能会省略该函数。 -
我似乎记得有一面旗帜可以融合相同的功能体,但似乎再也找不到了。。。
--ffunction-sections
将把每个函数放在自己的段中。这本身并不有用,但链接器可以使用--gc-sections
删除未使用的部分。现在,如果没有--ffunction-sections
,这只有在整个源文件未使用的情况下才能工作,即具有疯狂的粒度。
显然,您需要Matthieu提到的visibility属性,否则库中的所有函数都会因为可见而被"使用"。
这里已经讨论过:为什么我的C++输出可执行文件这么大?
基本上,查找调试符号、链接依赖关系的顺序、优化等等。。。
几个建议:
-
在可能的情况下,尝试重用相同的模板实例化(作为一个简单而人为的例子,
std::vector<int>
和std::vector<float>
将具有相同的内部结构,并且都可以将它们的元素数据视为不透明的4字节Blob,因此一个可以委托给另一个,并且只充当一个东西包装器,它只会强制转换回正确的类型,因此向量的内部只需要实例化一种类型,而不是两种类型 -
请尝试其他编译器。一些编译器在不会影响程序语义的地方重用相同的模板实例化,而另一些则更保守。
-
密切关注从库中导出的内容。链接器可以删除未导出且未在内部引用的符号。(当然,如果你正在构建一个静态库,只有当它链接到一个可执行文件中时,这才会生效。为了减少库本身的大小,你可以尝试将其变成一个动态库。)
但最终,听起来你可能只需要使用一个模板较少的库。(或者编写一个比目前更简单的解析器)
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 此代码是否违反一个定义规则
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 为什么在这个代码结束循环中没有得到结束
- 在c代码之间共享数据的最佳方式
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值