Clang IPO (LTO) support

This commit is contained in:
Ruslan Baratov 2017-04-28 17:13:56 +03:00
parent d828d0eb08
commit 7d057b2738
6 changed files with 118 additions and 9 deletions

View File

@ -0,0 +1,25 @@
if(NOT DEFINED _CMAKE_PROCESSING_LANGUAGE OR _CMAKE_PROCESSING_LANGUAGE STREQUAL "")
message(FATAL_ERROR "Internal error: _CMAKE_PROCESSING_LANGUAGE is not set")
endif()
# Try to find tools in the same directory as Clang itself
get_filename_component(__clang_hint_1 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" REALPATH)
get_filename_component(__clang_hint_1 "${__clang_hint_1}" DIRECTORY)
get_filename_component(__clang_hint_2 "${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER}" DIRECTORY)
set(__clang_hints ${__clang_hint_1} ${__clang_hint_2})
# http://manpages.ubuntu.com/manpages/precise/en/man1/llvm-ar.1.html
find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_AR NAMES
"${_CMAKE_TOOLCHAIN_PREFIX}llvm-ar"
HINTS ${__clang_hints}
DOC "LLVM archiver"
)
# http://manpages.ubuntu.com/manpages/precise/en/man1/llvm-ranlib.1.html
find_program(CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_RANLIB NAMES
"${_CMAKE_TOOLCHAIN_PREFIX}llvm-ranlib"
HINTS ${__clang_hints}
DOC "Generate index for LLVM archive"
)

View File

@ -28,12 +28,54 @@ else()
set(CMAKE_${lang}_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN "--gcc-toolchain=")
endif()
set(_CMAKE_IPO_SUPPORTED_BY_CMAKE NO)
set(_CMAKE_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)
set(_CMAKE_IPO_SUPPORTED_BY_CMAKE YES)
set(_CMAKE_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES)
unset(CMAKE_${lang}_COMPILE_OPTIONS_IPO)
unset(CMAKE_${lang}_ARCHIVE_CREATE_IPO)
unset(CMAKE_${lang}_ARCHIVE_APPEND_IPO)
unset(CMAKE_${lang}_ARCHIVE_FINISH_IPO)
string(COMPARE EQUAL "${CMAKE_${lang}_COMPILER_ID}" "AppleClang" __is_apple_clang)
# '-flto=thin' available since Clang 3.9 and Xcode 8
# * http://clang.llvm.org/docs/ThinLTO.html#clang-llvm
# * https://trac.macports.org/wiki/XcodeVersionInfo
set(_CMAKE_LTO_THIN TRUE)
if(__is_apple_clang)
if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 8.0)
set(_CMAKE_LTO_THIN FALSE)
endif()
else()
if(CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 3.9)
set(_CMAKE_LTO_THIN FALSE)
endif()
endif()
if(_CMAKE_LTO_THIN)
set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin")
else()
set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto")
endif()
if(ANDROID)
# https://github.com/android-ndk/ndk/issues/242
set(CMAKE_${lang}_LINK_OPTIONS_IPO "-fuse-ld=gold")
endif()
if(ANDROID OR __is_apple_clang)
set(__ar "${CMAKE_AR}")
set(__ranlib "${CMAKE_RANLIB}")
else()
set(__ar "${CMAKE_${lang}_COMPILER_AR}")
set(__ranlib "${CMAKE_${lang}_COMPILER_RANLIB}")
endif()
set(CMAKE_${lang}_ARCHIVE_CREATE_IPO
"${__ar} cr <TARGET> <LINK_FLAGS> <OBJECTS>"
)
set(CMAKE_${lang}_ARCHIVE_APPEND_IPO
"${__ar} r <TARGET> <LINK_FLAGS> <OBJECTS>"
)
set(CMAKE_${lang}_ARCHIVE_FINISH_IPO
"${__ranlib} <TARGET>"
)
endmacro()
endif()

View File

@ -915,6 +915,9 @@ void cmLocalGenerator::GetTargetFlags(
const char* libraryLinkVariable =
"CMAKE_SHARED_LINKER_FLAGS"; // default to shared library
const std::string linkLanguage =
linkLineComputer->GetLinkerLanguage(target, buildType);
switch (target->GetType()) {
case cmStateEnums::STATIC_LIBRARY:
this->GetStaticLibraryFlags(linkFlags, buildType, target);
@ -976,9 +979,6 @@ void cmLocalGenerator::GetTargetFlags(
linkFlags += this->Makefile->GetSafeDefinition(build);
linkFlags += " ";
}
const std::string linkLanguage =
linkLineComputer->GetLinkerLanguage(target, buildType);
if (linkLanguage.empty()) {
cmSystemTools::Error(
"CMake can not determine linker language for target: ",
@ -1040,6 +1040,8 @@ void cmLocalGenerator::GetTargetFlags(
default:
break;
}
this->AppendIPOLinkerFlags(linkFlags, target, config, linkLanguage);
}
void cmLocalGenerator::GetTargetCompileFlags(cmGeneratorTarget* target,
@ -1769,6 +1771,38 @@ void cmLocalGenerator::AppendFlagEscape(std::string& flags,
this->AppendFlags(flags, this->EscapeForShell(rawFlag));
}
void cmLocalGenerator::AppendIPOLinkerFlags(std::string& flags,
cmGeneratorTarget* target,
const std::string& config,
const std::string& lang)
{
if (!target->IsIPOEnabled(config)) {
return;
}
switch (target->GetType()) {
case cmStateEnums::EXECUTABLE:
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
break;
default:
return;
}
const std::string name = "CMAKE_" + lang + "_LINK_OPTIONS_IPO";
const char* rawFlagsList = this->Makefile->GetDefinition(name);
if (rawFlagsList == CM_NULLPTR) {
return;
}
std::vector<std::string> flagsList;
cmSystemTools::ExpandListArgument(rawFlagsList, flagsList);
for (std::vector<std::string>::const_iterator oi = flagsList.begin();
oi != flagsList.end(); ++oi) {
this->AppendFlagEscape(flags, *oi);
}
}
void cmLocalGenerator::AppendDefines(std::set<std::string>& defines,
const char* defines_list) const
{

View File

@ -115,6 +115,9 @@ public:
virtual void AppendFlags(std::string& flags, const char* newFlags);
virtual void AppendFlagEscape(std::string& flags,
const std::string& rawFlag);
void AppendIPOLinkerFlags(std::string& flags, cmGeneratorTarget* target,
const std::string& config,
const std::string& lang);
///! Get the include flags for the current makefile and language
std::string GetIncludeFlags(const std::vector<std::string>& includes,
cmGeneratorTarget* target,

View File

@ -457,6 +457,9 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags);
}
this->LocalGenerator->AppendIPOLinkerFlags(linkFlags, this->GeneratorTarget,
this->ConfigName, linkLanguage);
// Construct a list of files associated with this executable that
// may need to be cleaned.
std::vector<std::string> exeCleanFiles;

View File

@ -494,6 +494,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
// Create set of linking flags.
std::string linkFlags;
this->LocalGenerator->AppendFlags(linkFlags, extraFlags);
this->LocalGenerator->AppendIPOLinkerFlags(linkFlags, this->GeneratorTarget,
this->ConfigName, linkLanguage);
// Add OSX version flags, if any.
if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||