LTO с LLVM и CMake

Я пытаюсь применить Оптимизацию времени связи с LLVM в проекте CMake, который создает общую библиотеку. Мой вопрос почти такой же, как и этот:

Переключение между GCC и Clang/LLVM с помощью CMake.

Однако ответы больше не применимы, так как 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 дополнительные шаги?

Ответ 1

Правильный способ использования Clang и включения LTO использует флаг -flto в командной строке clang как во время компиляции, так и времени ссылки.

Кроме того, вам нужно будет работать на платформе с компоновщиком, который либо напрямую поддерживает LTO (обычно платформы Apple), либо имеет плагин LLVM-компоновщика (Linux с использованием компоновщика Gold, но я думаю, что некоторые из них получили BFD компоновщик для поддержки плагина компоновщика). Если вы используете плагин-компоновщик, вам нужно убедиться, что ваша установка LLVM построена и установлена ​​плагином. Если это произойдет, Clang автоматически добавит необходимые параметры командной строки компоновщика, чтобы использовать плагин при связывании с -flto, даже для общих объектов.

Кроме того, проект LLVM работает над новым компоновщиком (LLD), который будет поддерживать LTO из коробки на всех поддерживаемых платформах, но это все еще довольно рано. В настоящее время я знаю, что люди тестируют свою поддержку LTO в Windows и Linux, и, похоже, она работает хорошо, но по-прежнему не хватает многих функций.

Ответ 2

check_ipo_supported() приведен для меня в "" Политика CMP0069 не установлена" на CMake 3.9.1.

За свою помощь CMake до 3,8 поддерживает только Intel компилятор LTO. Для меня это тоже не работало на XCode 9.

Что работало, в конце концов:

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") не навредил.

Выберите вариант командной строки в зависимости от вашего компоновщика.

Более жестокая опция

В соответствии с ответом @ChandlerCarruth:

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

Ответ 3

Включение (тонкое) lto на Cmake 3.9 и новее должно быть простым:

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.