diff options
author | Ruslan Baratov <ruslan_baratov@yahoo.com> | 2017-04-28 14:13:56 (GMT) |
---|---|---|
committer | Ruslan Baratov <ruslan_baratov@yahoo.com> | 2017-04-28 14:13:56 (GMT) |
commit | 7d057b2738e229192ae5afe71d50354681813235 (patch) | |
tree | bebcaf0fcca709a89a4d6e9dde390ef7003cef38 | |
parent | d828d0eb084cf094119d2b47dae0053267aba138 (diff) | |
download | CMake-7d057b2738e229192ae5afe71d50354681813235.zip CMake-7d057b2738e229192ae5afe71d50354681813235.tar.gz CMake-7d057b2738e229192ae5afe71d50354681813235.tar.bz2 |
Clang IPO (LTO) support
-rw-r--r-- | Modules/Compiler/Clang-FindBinUtils.cmake | 25 | ||||
-rw-r--r-- | Modules/Compiler/Clang.cmake | 54 | ||||
-rw-r--r-- | Source/cmLocalGenerator.cxx | 40 | ||||
-rw-r--r-- | Source/cmLocalGenerator.h | 3 | ||||
-rw-r--r-- | Source/cmMakefileExecutableTargetGenerator.cxx | 3 | ||||
-rw-r--r-- | Source/cmMakefileLibraryTargetGenerator.cxx | 2 |
6 files changed, 118 insertions, 9 deletions
diff --git a/Modules/Compiler/Clang-FindBinUtils.cmake b/Modules/Compiler/Clang-FindBinUtils.cmake new file mode 100644 index 0000000..c81e77a --- /dev/null +++ b/Modules/Compiler/Clang-FindBinUtils.cmake @@ -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" +) diff --git a/Modules/Compiler/Clang.cmake b/Modules/Compiler/Clang.cmake index 6b99a08..8c2f87d 100644 --- a/Modules/Compiler/Clang.cmake +++ b/Modules/Compiler/Clang.cmake @@ -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() diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 57b744c..33e32d1 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -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 { diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 2eda0e5..1a238a8 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -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, diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 272d45b..fb39f01 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -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; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index ec01208..5ee9f45 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -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 || |