【问题标题】:c++ reduce library size by excluding unnecessary functions programmatically?c++ 通过以编程方式排除不必要的函数来减少库大小?
【发布时间】:2015-07-11 07:31:26
【问题描述】:

通过只选择需要的函数并删除不必要的文件来减少库大小的更简单方法是什么? 是否有脚本可以为 c++ 库完成此任务?

【问题讨论】:

  • 链接器通常会尝试自动检测哪些函数或至少是文件可以访问并删除不需要的函数。查看您的手册以了解如何进行设置。请注意,不必要地拖入东西仍然很容易,如果大小是一个问题,那么您应该偶尔浏览一下您的地图文件以了解实际情况。函数指针/工厂等表是常见的罪魁祸首,并且要注意从动态链接库中导出的内容。
  • 为什么你问?想要减少图书馆规模的情况是什么?通常没关系,因为库是共享的!请编辑您的问题以改进它,给出您的动机、上下文、您使用的编译器、操作系统、优化标志、实际库是什么等...
  • 为什么?链接器不会链接无法访问的库中的任何内容。你想解决什么问题?
  • 我正在链接 grt:github.com/nickgillian/grt(手势识别工具包),它是一个组织起来的模块集合,用于数据的预处理、特征提取、聚类、分类、回归和后处理。跨度>
  • 剥离不需要的模块看起来更像是一项人工工作。我正在尝试简化代码到多个平台的移植以避免麻烦。

标签: c++ optimization libraries minimize


【解决方案1】:

您可能应该首先尝试设置编译以最小化大小。您问题的答案很大程度上取决于编译器、链接器、操作系统、优化标志等...

在 Linux 上使用最近的 GCC 编译器 (g++),您应该尝试编译 并链接 优化大小 (-Os) 和 link time optimization (-flto) .

这么说

CXX=g++ -flto -Os

Makefile 的开头附近或在make clean 之后简单地运行make CXX='g++ -flto -Os'

顺便说一句,Clang/LLVM 也知道 -flto(并且像 GCC 一样使用 GOLD

请注意,共享的library(或者可能是 Microsoft 世界中的 DLL)需要包含所有代码(正是因为它在多个进程和程序之间共享)。您可以静态链接您的库(然后在构建静态库和将其链接到主程序时都使用g++ -flto -Os

很多时候,拥有共享库比试图减少它们的空间更有价值。

如果在 Linux 上,请阅读program library howto

【讨论】:

  • 不知道 -flto 选项,我会尝试向Cmake 开发人员发出功能请求以支持它。
  • cmake 中已经支持 LTO。你可以简单地尝试make clean 然后make CXX='g++ -flto -Os'
  • 这需要对 GCC 进行手动干预,我的意思是 CMake 已经自动使用某些编译器标志(例如,对于发布版本中的 GCC 使用 -O3),您是否真的声称 -flto 自动与某些在没有用户手动指定标志的情况下构建配置? (拥有该自动功能会很棒,因为您可以获得免费的优化,而实际上不必为 GCC 维护一个单独的标志,当您编译一个对 3 个不同编译器和 10 个编译器版本具有许多依赖关系的库时,这非常棒)。手动指定标志是众所周知的 cmake 反模式
  • 但是你应该阅读 cmake 文档。它确实知道 LTO。
  • 好吧,假设 Cmake 了解 LTO,如何在不提供特定于 GCC 的手动标志的情况下启用它?对生成的 makefile(尝试了所有构建配置)和文档进行文本搜索显示与 ltolink time optimization 不匹配。我当然有兴趣为 GCC 启用它。
【解决方案2】:

在典型的 C++ 应用程序中,模板代表大部分功能(例如 STL vectorstring 等)。这些函数仅在使用时才会生成为代码(尽管它们可能会生成为内联函数,在某些情况下会导致代码过大)。

链接器只会“挑选”您的应用程序所需的代码(当然包括您使用的函数调用的函数)。但是,例如 Linux 上的基本运行时非常大,因为它调用了很多功能,而这些功能又使用了相当多的其他功能 - 所以您的基本可执行文件大小非常大。在典型情况下,添加更多您自己的代码不会显着增加大小。

如果大小很重要,那么使用“小型 C++ 库”可能是一种选择——不同的操作系统可以使用不同的此类库。使用诸如-Os之类的选项让编译器告诉它“使代码变小”(换句话说,不要内联函数,除非内联代码比调用函数更短,并且不要展开循环,等等,等等——但是内联函数只调用一次,因为这确实使代码更短)

【讨论】:

  • 为什么每个人都认为他在使用 GCC,他甚至没有提到编译器。据我们所知,除非您使用编译器选项,否则他可能会使用默认生成几 MB 静态库的 Visual Studio,即使是几行代码也不例外
  • 我没有做出这样的假设。 gcc、clang 或 Visual Studio 的链接器的工作方式几乎相同,并且都使用-Os(与 armcc 一样)“针对小尺寸进行优化”。即使是我 30 年前使用的 Atari ST 编译器/链接器也只能包含实际使用的函数,所以我怀疑自 DOESN'T 以来生产的任何其他编译器......
【解决方案3】:

如果您不想对库进行大量重构(假设您可以访问源代码,但这并不总是一个现实的假设),是将其链接为静态库,或者作为应用程序的一部分进行编译:所有编译器都会从中受益。

请注意,与其他编译器相比,Clang 具有特殊的行为,因为它能够在静态链接时进行大量优化。

如果您出于某种原因不得不使用 DLL,您可以尝试调整导出符号的可见性(您可以隐藏客户端代码中不可见的符号并仅导出您使用的符号):请注意,这可能会启用一些优化速度和二进制大小,但可能是一项乏味的工作(我将其视为重大重构,因为有可能破坏事物)。

如果您正在使用依赖注入容器,您可能可以检测它们以警告未使用的依赖项,以便您可以轻松地将它们连接起来,而无需接触源代码(您对容器进行了一些重构,而不是对整个代码库进行了重构) 组合根目录中的源代码除外。

【讨论】:

猜你喜欢
  • 2015-05-19
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 2013-01-07
  • 2019-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多