summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRuslan Baratov <ruslan_baratov@yahoo.com>2017-04-28 14:13:56 (GMT)
committerRuslan Baratov <ruslan_baratov@yahoo.com>2017-04-28 14:13:56 (GMT)
commit7d057b2738e229192ae5afe71d50354681813235 (patch)
treebebcaf0fcca709a89a4d6e9dde390ef7003cef38
parentd828d0eb084cf094119d2b47dae0053267aba138 (diff)
downloadCMake-7d057b2738e229192ae5afe71d50354681813235.zip
CMake-7d057b2738e229192ae5afe71d50354681813235.tar.gz
CMake-7d057b2738e229192ae5afe71d50354681813235.tar.bz2
Clang IPO (LTO) support
-rw-r--r--Modules/Compiler/Clang-FindBinUtils.cmake25
-rw-r--r--Modules/Compiler/Clang.cmake54
-rw-r--r--Source/cmLocalGenerator.cxx40
-rw-r--r--Source/cmLocalGenerator.h3
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx3
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx2
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 ||