LLVM和CMake实现LTO

26

我正在尝试在使用CMake创建共享库的项目中,使用LLVM进行链接时优化(Link Time Optimization)。我的问题与此问题几乎相同。

然而,由于新版本中已经没有llvm-ld,因此答案似乎不再适用。在命令行中,我运行以下命令来获取LTO(假设只有2个.cpp文件):

将代码编译为字节码:

clang++ -c FirstClass.cpp -O3 -flto -o FirstClass.bc
clang++ -c SecondClass.cpp -O3 -flto -o SecondClass.bc

链接字节码:

llvm-link FirstClass.bc SecondClass.bc -o unoptimized.bc

优化字节码:

opt -O3 unoptimized.bc -o optimized.bc

将字节码转换为共享对象:

clang++ -shared optimized.bc -o libTest.so

有人可以告诉我如何让CMake运行额外的步骤吗?


2
这可能是cmake的add_custom_command的工作... 类似于add_custom_command(OUTPUT libTest.so COMMAND clang++ -shared optimized.bc -o libTest.so MAIN_DEPENDENCY optimized.bc) 参见https://dev59.com/R2Yr5IYBdhLWcg3ws8NT - francis
请参见 https://dev59.com/yV0Z5IYBdhLWcg3whApv。 - pooya13
3个回答

22
正确的使用Clang并启用LTO的方法是,在编译和链接时都在clang命令行中使用-flto标志。此外,您需要在支持LTO的平台上工作,并配备直接支持LTO(例如Apple平台)或具有LLVM链接器插件(如Linux使用Gold链接器,但我认为某些人已经使BFD链接器支持了链接器插件)。如果您使用链接器插件,则需要确保LLVM的安装版本构建并安装了该插件。如果是这样,当使用-flto进行链接时,Clang将自动添加必要的链接器命令行选项以使用插件,即使用于共享对象也是如此。此外,LLVM项目正在开发新的链接器(LLD),它将在其支持的所有平台上原生支持LTO,但目前尚处于早期阶段。目前,我知道有人正在测试其在Windows和Linux上的LTO支持,看起来效果不错,但仍缺少许多功能。

3

check_ipo_supported()在CMake 3.9.1中导致了"策略CMP0069未设置"的错误。

根据其帮助文档,CMake在3.8之前仅支持Intel编译器的LTO。对于我使用的XCode 9的clang也不起作用。

最终有效的解决方法:

cmake_policy(SET CMP0069 NEW)
include(CheckIPOSupported)
check_ipo_supported()

add_executable(Foobar SOURCES)
set_target_properties(Foobar PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)

看起来 add_executable() 需要在 cmake_policy(SET CMP0069 NEW) 之后。

LTO 缓存

target_link_libraries(Foobar "-Wl,-cache_path_lto,${PROJECT_BINARY_DIR}/lto.cache") 没有造成伤害。

根据你的链接器选择命令行选项 depending on your linker

更加暴力的选项

根据 @ChandlerCarruth 的回答:

if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
    target_link_libraries(Foobar -flto)
endif ()

2

在Cmake 3.9及以上版本上启用(瘦)lto应该很简单:

include(CheckIPOSupported)
check_ipo_supported()
set_target_properties(myProject PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)

不再针对每个项目使用set_target_properties,可以设置单个全局的set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)

为了加快重新编译的速度,可以设置 LTO 缓存:

function(append value)
    foreach(variable ${ARGN})
        set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
    endforeach(variable)
endfunction()

append("-fuse-ld=gold -Wl,--no-threads,--plugin-opt,cache-dir=${PROJECT_BINARY_DIR}/lto.cache" CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS)

为了使用正确的命令行选项,需要强制使用gold作为链接器。这可能需要将/usr/lib/LLVMgold.so符号链接到/usr/lib/llvm-4.0/lib/LLVMgold.so


1
请注意,在使用全局设置时,必须在添加目标之前定义它。 - mrks
3
有没有办法让cmake传递-flto而不是-flto = thin? - Indiana Kernick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接