C++ 如何减少模板繁重的C++;密码?

C++ 如何减少模板繁重的C++;密码?,c++,templates,boost-spirit,C++,Templates,Boost Spirit,我有个大问题。我有一个公共库,在我的项目中都使用。此库大量使用boost.spirit和boost.fusion。不幸的是,库的大小约为700Mb。所有的boost.spirit-重码都被使用了,效果很好。可以采取哪些步骤来减少其输出大小?是否有一个工具可以帮助确定哪些模板实例化浪费了大部分空间 首先,我决定将所有支持spirit的代码移到cpp文件中。其次,我将尝试使用不同的编译器标志来优化大小。我不知道还能做什么 更新(详细信息) 我正在使用GNU工具链。巨大的图书馆实际上是一个静态图书馆。

我有个大问题。我有一个公共库,在我的项目中都使用。此库大量使用
boost.spirit
boost.fusion
。不幸的是,库的大小约为700Mb。所有的boost.spirit-重码都被使用了,效果很好。可以采取哪些步骤来减少其输出大小?是否有一个工具可以帮助确定哪些模板实例化浪费了大部分空间

首先,我决定将所有支持spirit的代码移到cpp文件中。其次,我将尝试使用不同的编译器标志来优化大小。我不知道还能做什么

更新(详细信息)

我正在使用GNU工具链。巨大的图书馆实际上是一个静态图书馆。使用这个700Mb库的可执行文件大小为200Mb。至少一半代码在*.h文件中。一些
boost.spirit
语法(非常重的模板)也位于*.h文件中

干杯

一些建议:

  • 在可能的情况下,尝试重用相同的模板实例化(作为一个简单而人为的例子,
    std::vector
    std::vector
    将具有相同的内部结构,并且两者都可以将其元素数据视为不透明的4字节blob,这样一个就可以委托给另一个,只是充当一个东西包装器,只需将其转换回正确的类型,这样向量的内部就可以ly必须为一种类型而不是两种类型实例化

  • 尝试不同的编译器。有些编译器重用相同的模板实例化,但不会影响程序语义,而另一些编译器则比较保守

  • 密切关注从库中导出的内容。链接器可以删除未导出和未在内部引用的符号。(当然,如果您正在构建一个静态库,则在它链接到可执行文件之前,这不会生效。要减小库本身的大小,您可以尝试将其改为动态库)


但最终,听起来您可能只需要使用一个模板较少的库(或者编写一个比当前更简单的解析器)

这里已经讨论过:


基本上,查找调试符号、链接依赖项顺序、优化等…

将支持spirit的代码移动到
.cpp
文件是一个很好的第一步,尽管您提到头文件中有spirit语法,但这可能是不完整的

  • 确保从未将任何语法/规则导出到库外。如果您有典型的
    include
    /
    src
    目录,则将这些文件(即使是标题)移动到
    src
    目录中

  • 将所有这些符号标记为库的内部符号。它们不应从库外部访问。根据编译器的不同,在gcc查找中有特定的pragma/属性:
    \uuuu属性(可见性(“内部”))
    。这有助于编译器相应地优化它们,特别是编译器可能会发出函数的代码,即使它在给定的调用站点将其内联,以防使用此函数地址。但是,由于具有内部可见性,它知道代码不会离开对象,因此可能会省略函数

  • 我似乎记得一个融合相同功能体的标志,但似乎再也找不到了

  • --ffunction sections
    会将每个函数放在自己的段中。这本身并不有用,但链接器可以使用
    --gc sections
    删除未使用的段。现在,如果没有
    --ffunction sections
    ,这只会在整个源文件未使用的情况下起作用,即粒度不合理


    显然,您需要Matthieu提到的可见性属性,否则库中的所有函数都将被“使用”由于是可见的。

    重用模板实例化的问题之一是,通常每个函数都应该有不同的地址,这会阻止将不同的函数正确地融合在一起,即使它们的可执行代码是不同的。我认为VC++不太关心这一点,无论从严格意义上讲,这种优化是在进行的如果编译器能够证明程序中没有使用地址,那么它将是可用的…@MatthieuM。没错,这就是为什么不是所有编译器都这样做的原因。这通常是一种非常安全的优化(你不经常比较函数地址,当你这样做的时候,我怀疑在大多数情况下它是无效的,编译器检测它是相当简单的)——然而,它确实为模板重代码的可执行大小创造了奇迹感谢
    可见性
    属性,我不知道它。