我最近发现了 LLVM 的链接器 lld
,它因非常快速的链接而受到称赞。事实上,我对其进行了测试,结果非常棒,与 gold
相比,我的案例中的链接时间大大减少了。
但是,在谈到链接时优化时,我的知识是有限的。据我通过阅读互联网上的资料了解到,目标文件中产生了一些额外的代码,代表了一些内部编译器结构,然后在链接阶段使用这些代码。因此,我担心链接时优化(及其好处)是否会受到此编译器/链接器组合的影响。我将不胜感激对此事的一些解释!
我使用的是 gcc
版本 9.2.0
和 lld
版本 10.0.0
。
我用来生成目标文件的命令:
/opt/gcc/9.2.0/bin/c++ -fPIE -flto -ffat-lto-objects -fuse-linker-plugin -m64 -O3 -g -DNDEBUG -o my_object.cpp.o -c my_source_file.cpp
链接:
#-fuse-ld=gold
/opt/gcc/9.2.0/bin/c++ -fPIE -flto -ffat-lto-objects -fuse-linker-plugin -m64 -pie -fuse-ld=gold -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -static-libstdc++ -static-libgcc -Wl,--threads -Wl,--thread-count,1
#-fuse-ld=lld
/opt/gcc/9.2.0/bin/c++ -fPIE -flto -ffat-lto-objects -fuse-linker-plugin -m64 -pie -fuse-ld=lld -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -static-libstdc++ -static-libgcc -Wl,--threads -Wl,
最佳答案
我做了一些研究,最后自己得出结论,如果我们在用 gcc
编译时使用 lld
,则不会完成 LTO。我做了什么:
基于这个有些模糊的介绍:https://www.slideshare.net/chimerawang/gcc-lto ,我发现链接器并没有直接进行优化,而是在读取了所有目标文件中的所有符号后,将信息传递给 lto-wrapper
,然后后者通过一些其他过程。因此,我使用 hello-world
cpp 文件进行了测试,并使用 -v
标志对其进行了编译,实际上我看到了前面提到的连续调用(collect2
(链接器)-> lto-wrapper
-> lto1
)。但这是在使用默认链接器或 gold
链接器时。当我使用 -fuse-ld=lld
标志时,只有 collect2
进程被调用。这第一件事让我相信 LTO 根本没有完成。
但是,嘿,也许 lld
链接器内化了 LTO 进程,因此无需调用任何其他进程即可完成。所以我做了另一个测试,看看 LTO 是否完成(基于 this 文章)。基本上,我从一个 cpp 文件中调用了 100 000 000 次在其他 cpp 文件中定义的函数,该函数什么都不做。使用基本的 -O2
优化,生成的二进制文件运行时间约为 200 毫秒,因为编译器无法优化无用的函数调用。当同时使用 -flto
标志和 ld
或 gold
链接器时,生成的二进制文件运行时间约为 2 毫秒。但是当使用 lld
链接器时,生成的二进制文件也会在 ~200 毫秒内运行。所以带 lto 的 lld
运行速度和不带 lto 的 lld
一样慢。没有任何优化迹象。
在这里要提到的是,使用 lld
链接器,如果对象不使用 -ffat-lto-objects
编译,链接命令将失败。此标志使目标文件更大,因为编译器不仅转储 lto 代码,还转储无需 lto 即可链接的代码。
因此,考虑到与 lld
链接的二进制文件的时间性能以及需要使用 -ffat-lto-objects
编译对象的事实,我得出结论当使用 lld
链接器时,根本没有实现 LTO,但是 lld
使用编译器生成的非 LTO 代码来链接二进制文件。
关于c++ - 使用 GCC 编译但链接 LLVM LLD 时 LTO 是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58084395/