微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么我用 -LTO 构建的 C++ 二进制文件如此之大?

如何解决为什么我用 -LTO 构建的 C++ 二进制文件如此之大?

我正在 Mac 上编译一些二进制文件,但是使用更新的编译器编译后的大小变得很大(从之前的 ~5MB 增加到 ~20MB)。我认为这与之前未激活的 LTO(链接时间优化)有关。我在 linux 上没有观察到这个文件膨胀。

在玩弄 strip 之后(尽管尝试基于带有标志 -S -x 的 Xcode 并且也没有标志,以及由带有标志 {{1} },所有这些似乎都具有相同的效果)我发现了这个工具:https://github.com/google/bloaty Bloaty McBloated,当在我的二进制文件上运行时,它会产生这个输出

-s

那么谁能告诉我这些巨大的 FILE SIZE VM SIZE -------------- -------------- 53.9% 9.72Mi 53.8% 9.72Mi __GNU_LTO,__wrapper_sects 32.5% 5.86Mi 32.4% 5.86Mi __GNU_DWARF_LTO,__debug_info 6.2% 1.11Mi 6.2% 1.11Mi __TEXT,__text 2.2% 403Ki 2.2% 403Ki __TEXT,__eh_frame 1.6% 298Ki 1.6% 298Ki __GNU_LTO,__wrapper_names 1.0% 177Ki 1.0% 177Ki Export Info 0.7% 131Ki 0.7% 131Ki Weak Binding Info 0.4% 77.0Ki 0.4% 77.0Ki __GNU_DWARF_LTO,__debug_str 0.4% 75.8Ki 0.4% 75.8Ki __DATA,__gcc_except_tab 0.2% 44.6Ki 0.2% 44.6Ki __GNU_LTO,__wrapper_index 0.2% 39.4Ki 0.2% 39.4Ki __DATA_CONST,__const 0.2% 33.1Ki 0.2% 33.1Ki __GNU_DWARF_LTO,__debug_abbrev 0.1% 26.4Ki 0.1% 26.4Ki __GNU_DWARF_LTO,__debug_line 0.1% 21.7Ki 0.1% 23.6Ki [20 Others] 0.1% 19.0Ki 0.1% 19.0Ki __TEXT,__text_cold 0.1% 18.1Ki 0.1% 18.1Ki __TEXT,__const 0.0% 8.82Ki 0.0% 8.82Ki __TEXT,__text_startup 0.0% 8.60Ki 0.0% 8.60Ki __TEXT,__cstring 0.0% 0 0.0% 7.18Ki __DATA,__pu_bss5 0.0% 0 0.0% 6.88Ki __DATA,__bss5 0.0% 5.87Ki 0.0% 5.87Ki __DATA,__la_symbol_ptr 100.0% 18.1Mi 100.0% 18.1Mi TOTAL 部分是做什么用的,以及如何通过后处理或向我的构建链添加编译标志来摆脱它们。

OS 是 MacOS,我使用的是 g++ 10,这里有完整的跟踪: https://github.com/yanntm/testGithbuActions/runs/1778387086?check_suite_focus=true

为了更好的可移植性,我正在尝试尽可能多地编译静态。然而,二进制文件仍然动态链接到 /usr/lib/libSystem.B.dylib(我显然不能用 libtool 静态链接这个)。

我不想要任何调试符号,因为这是面向最终用户的生产二进制文件

解决方法

你会找到答案in gcc's documentation

链接时间优化作为 GCC 前端实现 在特殊部分发出的 GIMPLE 的字节码表示 .o 文件。

[ ... ]

由于 GIMPLE 字节码与最终目标代码一起保存,因此对象 使用 LTO 支持生成的文件比常规目标文件大。

[ ... ]

当前的实现只产生“胖”对象,有效地 编译时间加倍,文件大小增加 5 倍 原始尺寸。

但是等等,还有更多。您仅使用 -flto 构建。如果您还使用了 -ffat-lto-objects,那么,如 gcc 的信息页面所述:

'-ffat-lto-objects'

Fat LTO 对象是包含中间文件的对象文件 语言和目标代码。这使它们可用于 LTO 链接和正常链接。此选项仅在以下情况下有效 使用“-flto”编译并在链接时被忽略。

尝试使用 strip 将是徒劳的。 strip 仅去除调试数据。这不是调试数据,而是基本上半编译的 C++ 代码,最终编译作为链接周期的一部分发生。如果您想“摆脱它们”,请不要使用 LTO。

编辑:某些 gcc/binutils 配置可能会在目标二进制文件中留下 LTO 部分。我查看了 Fedora 的默认 rpmbuild 配置,它默认使用 LTO 构建,但不会遭受相同的可执行文件膨胀。

事实证明,Fedora 的 rpmbuild 执行了一个 brp-strip-lto 脚本,可归结为:

sh -c "$STRIP -p -R .gnu.lto_* -R .gnu.debuglto_* -N __gnu_lto_v1 \"\$@\"" ARG0

关键选项是两个 -R 选项,不清楚 __gnu_lto_v1 符号是什么,被 -N 删除。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。