- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在编写代码或构建脚本以使用 LTO 进行编译时需要牢记哪些注意事项和陷阱?
这个问题背后的动机是为了更好地理解为什么某些项目在启用 LTO 时编译不干净。特别是,我无法构建 ICU在启用 LTO 的情况下,既不在 MSVC 中也不在 GCC 中。在其他情况下,我可以使用给定的工具链版本启用 LTO,但不能使用另一个(更新的)版本;例如,libiconv 会发生这种情况.
在我遇到的所有失败案例中,都涉及由于未解析符号导致的链接失败。
为什么会发生这种情况?这是工具链、构建脚本或源代码的问题吗?
最佳答案
这个答案总结了我在 GCC 和 MSVC 中构建启用了 LTO 的项目时所涉及的一些复杂问题的发现。
首先,根据 GCC Wiki ,为了正确构建启用了 LTO 的项目,您必须:
gcc-ar
而不是 binutils ar
;gcc-ranlib
而不是 binutils ranlib
;gcc-nm
而不是 binutils nm
;-flto
编译和链接。这意味着在传统的./configure && make
循环中,必须介意设置AR=
、RANLIB=
和NM=
相关时。主要是这样;但是,这些步骤很容易被忽略,因为需要更改 eg 的值。 AR
并不常见。
现在的问题:
在 GCC 4.8 及更早版本中,编译器默认生成胖目标文件。这意味着即使后编译工具(链接器、存档器等)无法识别 LTO 对象,它们也能正常工作(但不会实际执行 LTO)。
在 GCC 4.9 及更高版本中,编译器默认发出 slim 对象文件,这意味着编译后工具必须识别 LTO 对象,否则工具将失败。这解释了为什么有时 LTO 构建在使用 GCC 4.8 时通过,但在使用 GCC 4.9 及更高版本时失败。
我还注意到构建脚本并不总是在需要时将某些配置指令的值正确传递给子脚本。例如,在 MinGW-w64 中使用 LTO 构建静态 libiconv
时,configure 脚本仍然使用 ar
而不是 配置内部
,即使被告知 libtool
gcc-arAR=gcc-ar
。
LTO 构建往往会发现隐藏的错误,特别是由 static init order fiasco 引起的错误.它们还会妨碍其他优化,例如 ICF(由 Gold 执行)。
最后,LTO 机器中显然仍然存在一些错误。当尝试使用启用了 LTO 和其他优化的 MinGW-w64 编译 ICU 时,我遇到了 this bug和内部编译器错误(internal compiler error: in splice_child_die, at dwarf2out.c
,可能与使用 -g
和 LTO 有关)。
所有这一切都意味着,由于工具链中的一些缺陷,使用 LTO 构建一个随机项目仍然很重要。有些项目会成功构建,有些则不会。
在MSVC中使用LTO编译(也就是LTCG),编译时必须使用/GL
,链接时必须使用/LTCG
,就是这样.
尽管如此,当在 MSVC 中启用 LTCG 时,编译器不会发出传统的 COFF 对象。它发出一个 special kind of object file包含其 header (ANON_OBJECT_HEADER_BIGOBJ
) 与 COFF header (IMAGE_FILE_HEADER
) 不同的 IR。这显然在构建项目时应该没有任何区别,因为这些细节留给工具链来处理。
现在,为什么在 MSVC 中启用 LTCG 后 ICU 无法正确构建?
ICU 有一个名为 pkgdata
的工具,它可以为给定的体系结构生成目标代码。在构建过程中,该工具用于构建包中的其他实用程序。但是,pkgdata
会尝试通过检查给定的引用对象文件来猜测目标体系结构。在 Windows 中,该工具采用 COFF header ,并且在 32 位构建中它错误地确定目标是 64 位架构(由于 pkg_genc.c:getArchitecture()
中的草率逻辑) .因此 MSVC 32 位 LTCG 构建失败。
关于c++ - 如何编写支持 LTO 的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42230141/
我正在使用 CMake 为我的 C 编译启用 IPO(过程间优化): set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRU
我正在使用 CMake 为我的 C 编译启用 IPO(过程间优化): set_property(TARGET foo PROPERTY INTERPROCEDURAL_OPTIMIZATION TRU
我一直在尝试使用以下代码片段(gcc 编译时没有任何警告)更改 Windows(7 和 Server 2012 R2)中 LTO8 磁带的事件分区: DWORD partition= 2; if(Se
考虑以下程序: #include #include int main() { std::string s; std::getline(std::cin, s);
我正在使用链接时间优化 (lto) 和 O2 优化级别编译一个带有修改版 clang 的项目。 O0 和 O1 都很好,但遗憾的是 O2 删除了一些函数调用。有没有办法告诉优化忽略特定功能?我已经尝试
我有带闪存的 MCU(像往常一样)。链接器将 .struct_init、.struct_init_const、.struct_not_init 部分放置到属于闪存部分 20 的地址。它在链接器脚本中被
在编译翻译单元时,编译器会进行大量优化 - 内联、常量折叠/传播、别名分析、循环展开、死代码消除以及许多我从未听说过的其他优化。在多个翻译单元之间使用 LTO/LTCG/WPO 时是否全部完成,或者只
比较 C++ 中的虚函数和 C 中的虚表,编译器在一般情况下(以及对于足够大的项目)在去虚拟化方面是否同样出色? 天真地,C++ 中的虚函数似乎具有更多的语义,因此可能更容易去虚拟化。 更新: Moo
GCC、MSVC、LLVM 和可能的其他工具链支持链接时间(整个程序)优化,以允许优化编译单元之间的调用。 编译生产软件时是否有理由不启用此选项? 最佳答案 我假设 “生产软件” 是指您交付给客户/投
有没有办法检测代码是否是用 -flto 编译的? 示例是Linux下的经典库或可执行文件,使用GCC(4.9.1)编译,无需调试。 最佳答案 考虑到 LTO 信息存储在目标文件内的几个 ELF 部分中
假设我有一个函数 void do_something() { //.... #ifdef FEATURE_X feature_x(); #endif /
对于 gcc,这个 answer告诉我们如何验证链接时间优化是否已执行。对于 clang,我看不到任何类似于 .gnu.lto 的条目. 更具体地说,我有一个二进制文件,我很确定 LTO 应该有很大的
我试图用下一个标志编译我的源代码: 1. -flto2. -flto -ffat-lto-objects3. -flto -fno-fat-lto-objects 第三个提供优化slim文档中编写的
我有一个项目,在 ARM Cortex-M4 处理器上运行,我试图在其中包含 gcc 链接时优化 (LTO) 功能。 目前我的编译和链接标志是: CFLAGS = -ggdb -ffunction-s
在编写代码或构建脚本以使用 LTO 进行编译时需要牢记哪些注意事项和陷阱? 这个问题背后的动机是为了更好地理解为什么某些项目在启用 LTO 时编译不干净。特别是,我无法构建 ICU在启用 LTO 的情
我想使用符号版本控制和链接时优化 (LTO) 编译共享库。但是,一旦我打开 LTO,一些导出的符号就会消失。这是一个最小的例子: 首先定义函数 fun 的两个实现: $ cat fun.c #incl
当我尝试使用 -flto 构建静态库时,出现 undefined reference 错误: library.cpp: #include void foo() { std::cout << "T
Clang 允许使用瘦 lto 来加快编译时间,同时仍然保留使用 lto 和选项 -flto=thin 的大部分优点。 . gcc 有相当于 clang 的薄 lto 吗? 最佳答案 GCC 有一个相
我正在使用 arm-none-eabi-gcc 为基于 Cortex-M4 的微 Controller 编译一个可执行文件。非性能关键代码使用 -Os(针对可执行代码大小进行了优化)编译,性能关键部分
有这样的代码: #include "kernel.h" int main() { ... for (int t = 0; t 1099: 00 109a: f
我是一名优秀的程序员,十分优秀!