如何在CMake中启用链接时优化(LTO)?

53

我已经拥有最新的cmake构建,并尝试所有的构建配置(Debug、MinSizeRel、RelWithDebugInfo、Release、General),但在生成的makefile中(文本搜索)找不到字符串"-lto",因此这个功能可能还没有出现,或者需要手动干预。在这种情况下,对文档进行LTO(链接时间优化)或者LTO的文本搜索都没有结果,因此在官方文档中没有启用LTO的方法。

是否有一种全局启用LTO的方法(适用于所有编译器),而不必手动指定标志,这些标志最坏的情况下仅受到GCC的支持?


3
现在,CMake不支持LTO的跨平台。你应该通过添加所需的编译选项和使用相应的工具(如gcc-argcc-nmgcc-ranlib而不是默认值)来自己添加它,因为据我所知,binutils现在也没有完全准备好这个功能。 - zaufi
5个回答

104

好消息!CMake v3.9 最终支持 LTO


示例

以下是一个示例代码,展示它的工作原理:

cmake_minimum_required(VERSION 3.9.4)

include(CheckIPOSupported)
check_ipo_supported(RESULT supported OUTPUT error)

add_executable(example Example.cpp)

if( supported )
    message(STATUS "IPO / LTO enabled")
    set_property(TARGET example PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
else()
    message(STATUS "IPO / LTO not supported: <${error}>")
endif()

对于GCC,这会将-flto -fno-fat-lto-objects添加到目标编译命令中。


检查编译器支持

模块CheckIPOSupported提供检查编译器是否支持过程间优化(IPO/LTO)的功能:

check_ipo_supported([RESULT <result>] [OUTPUT <output>]
                    [LANGUAGES <lang>...])
如果没有传递参数(即check_ipo_supported()),则会引发错误以指示不支持,否则result变量将设置为YESNO。有关详细信息,请参阅模块的文档。
启用LTO LTO可以针对单个目标或作为所有目标的默认启用。
单个目标的LTO 要为目标启用LTO,请将INTERPROCEDURAL_OPTIMIZATION设置为TRUE。这可以通过set_property()命令完成:
set_property(TARGET name-target-here
             PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)

将LTO设置为默认

你可以通过将CMAKE_INTERPROCEDURAL_OPTIMIZATION设置为TRUE来启用默认的LTO:

set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)

在此行之后创建的所有目标将启用INTERPROCEDURAL_OPTIMIZATION,但在此行之前创建的目标不受影响。


另请参阅


2
对于默认的LTO:“对于此行之后创建的所有目标”,这应该也会影响子项目(例如从add_subdirectory)是吗? - svenevs
5
简短回答:是的。 - ollo
为什么一个构建工具需要支持特定的编译器选项?!?! - user8434768
1
我发现CMAKE_INTERPROCEDURAL_OPTIMIZATION比为每个目标单独设置INTERPROCEDURAL_OPTIMIZATION更可靠,并且混合具有和不具有LTO的目标似乎效果不佳。使用Clang时,在将LTO-ed库链接到非LTO目标时会出现链接错误。此外,对于MSVC,为各个目标设置LTO会导致链接器抱怨其与增量链接不兼容。 - Alexey B.
2
我为什么要自己检查支持呢?编辑:https://cmake.org/cmake/help/git-stage/policy/CMP0069.html - Trass3r
显示剩余3条评论

16

更新:截至2015年10月28日,CMake IRC上

jcelerier | I have a question about INTERPROCEDURAL_OPTIMIZATION
jcelerier | it sounds like it should enable -flto on gcc
+ngladitz | jcelerier: its only implemented for the intel compiler
jcelerier | ngladitz: ah, okay
jcelerier | are there other switches for pgo / lto ?
jcelerier | or must it be done by hand ?
+ngladitz | there currently is no first class support otherwise     

相关的 CMake 问题:https://gitlab.kitware.com/cmake/cmake/issues/15245


CMake 有一个名为 INTERPROCEDURAL_OPTIMIZATION 的属性,听起来可能会在某些平台上启用 LTO。

链接:http://www.cmake.org/cmake/help/v3.0/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.html

要在目标“ MyLib”上启用它:

add_library(MyLib ...)
...
set_property(TARGET MyLib PROPERTY INTERPROCEDURAL_OPTIMIZATION True)

1
CMake文档非常缺乏,为了完整起见,有人应该如何在CMake脚本中启用该标志? - CoffeDeveloper
@darioOO 已添加到答案中。 - Jean-Michaël Celerier
4
这似乎是使用CMake的方式来做。然而,在Debian Jessie上测试时,使用CMake 3.0和gcc 4.9.2以及clang 3.5.0,这似乎没有激活任何与lto相关的编译器标志。:-/ - LeSpocky
已根据要求修改了我的答案。 - Jean-Michaël Celerier

1

根据源代码,gcc/clang编译器不支持LTO,只有Intel编译器有一些支持。

我有一些cmake 3.4.3的grep输出:

grep -HiR 'INTERPROCEDURAL_OPTIMIZATION' *
Help/manual/cmake-properties.7.rst:  
/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG
Help/manual/cmake-properties.7.rst:  
/prop_dir/INTERPROCEDURAL_OPTIMIZATION
Help/manual/cmake-properties.7.rst:  
/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG
Help/manual/cmake-properties.7.rst:  
/prop_tgt/INTERPROCEDURAL_OPTIMIZATION
Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION.rst:INTERPROCEDURAL_OPTIMIZATION
Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst:INTERPROCEDURAL_OPTIMIZATION_<CONFIG    
Help/prop_dir/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst:This is a
per-configuration version of INTERPROCEDURAL_OPTIMIZATION.
Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst:INTERPROCEDURAL_OPTIMIZATION
Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst:INTERPROCEDURAL_OPTIMIZATION_<CONFIG    
Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION_CONFIG.rst:This is a
per-configuration version of INTERPROCEDURAL_OPTIMIZATION.
Modules/Platform/Linux-Intel.cmake:    # INTERPROCEDURAL_OPTIMIZATION
Source/cmCommonTargetGenerator.cxx: 
if(this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION"))
Source/cmGeneratorTarget.cxx:          
"INTERPROCEDURAL_OPTIMIZATION", config))
Source/cmMakefileLibraryTargetGenerator.cxx: 
if(this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION") &&
Tests/IPO/CMakeLists.txt:set_property(DIRECTORY PROPERTY
INTERPROCEDURAL_OPTIMIZATION 1)

正如您所看到的,我们只有英特尔平台模块。

因此,我已经为这个非常实用的功能创建了一个特性请求:https://cmake.org/Bug/view.php?id=15939


1
在一个项目中重新讨论这个问题,我必须包含一个不可变子项目的cmake配置,似乎最强有力的方法是在定义任何目标或包含任何内容之前添加以下内容来启用LTO:
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)

这样做可以启用LTO并且即使后续包含的项目没有通过CheckIPOSupported处理LTO,也能让CMAKE保持安静。

-2

目前gcc和clang都支持lto。 (参见:https://clang.llvm.org/docs/CommandGuide/clang.html https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html ) 您可以通过cmake启用它: set (CMAKE_INTERPROCEDURAL_OPTIMIZATION True) 但是,您需要具有版本cmake>= 3.9,并且我认为可能需要设置一些策略并检查编译器/工具链是否支持LTO(检查CMAKE_IPO_AVAILABLE并在否则抛出错误)

并为gcc / clang设置标志(-flto和-ffat-lto-files用于fcc>4.7或-flto = full / thin用于clang)


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