From 6e3655db2cc8202424e54bdde83e4240eb680cc3 Mon Sep 17 00:00:00 2001 From: Zsolt Parragi Date: Mon, 8 Jul 2019 18:52:23 +0200 Subject: Clang: add LTO support for GNU-command line clang on windows --- Modules/Platform/Windows-Clang.cmake | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake index 728e0b9..6a12381 100644 --- a/Modules/Platform/Windows-Clang.cmake +++ b/Modules/Platform/Windows-Clang.cmake @@ -44,15 +44,22 @@ macro(__windows_compiler_clang_gnu lang) set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 1) set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1) + set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto") + set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES) + set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES) + set(CMAKE_${lang}_ARCHIVE_CREATE_IPO " cr ") + set(CMAKE_${lang}_ARCHIVE_APPEND_IPO " r ") + set(CMAKE_${lang}_ARCHIVE_FINISH_IPO " ") + # Create archiving rules to support large object file lists for static libraries. set(CMAKE_${lang}_ARCHIVE_CREATE " qc ") set(CMAKE_${lang}_ARCHIVE_APPEND " q ") set(CMAKE_${lang}_ARCHIVE_FINISH " ") set(CMAKE_${lang}_CREATE_SHARED_LIBRARY - " -nostartfiles -nostdlib -o ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /implib: -Xlinker /pdb: -Xlinker /version:. ") + " -fuse-ld=lld-link -nostartfiles -nostdlib -o ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /implib: -Xlinker /pdb: -Xlinker /version:. ") set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY}) set(CMAKE_${lang}_LINK_EXECUTABLE - " -nostartfiles -nostdlib -o -Xlinker /implib: -Xlinker /pdb: -Xlinker /version:. ${CMAKE_GNULD_IMAGE_VERSION} ") + " -fuse-ld=lld-link -nostartfiles -nostdlib -o -Xlinker /implib: -Xlinker /pdb: -Xlinker /version:. ${CMAKE_GNULD_IMAGE_VERSION} ") set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmt) set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL -D_DLL -D_MT -Xclang --dependent-lib=msvcrt) -- cgit v0.12 From 079b8e29168dc081f37f79f3577a5c0690bb7051 Mon Sep 17 00:00:00 2001 From: Zsolt Parragi Date: Thu, 11 Jul 2019 16:55:19 +0200 Subject: Clang: prefer lld-link over link.exe Objects compiled with -flto can only be linked with the llvm linker. Before this change, clang-cl only supperted IPO with manual linker selection. --- Modules/CMakeFindBinUtils.cmake | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake index 773ee53..01f9dae 100644 --- a/Modules/CMakeFindBinUtils.cmake +++ b/Modules/CMakeFindBinUtils.cmake @@ -69,7 +69,12 @@ if(("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_SIMULATE_ID}" STREQUAL "xMSVC" AND OR (CMAKE_GENERATOR MATCHES "Visual Studio" AND NOT CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android")) - find_program(CMAKE_LINKER NAMES link HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + if("x${CMAKE_${_CMAKE_PROCESSING_LANGUAGE}_COMPILER_ID}" STREQUAL "xClang") + find_program(CMAKE_NM NAMES ${_CMAKE_TOOLCHAIN_PREFIX}nm llvm-nm HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) + set(_CMAKE_ADDITIONAL_LINKER_NAMES "lld-link") + endif() + + find_program(CMAKE_LINKER NAMES ${_CMAKE_ADDITIONAL_LINKER_NAMES} link HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) find_program(CMAKE_MT NAMES mt HINTS ${_CMAKE_TOOLCHAIN_LOCATION}) list(APPEND _CMAKE_TOOL_VARS LINKER MT) @@ -115,6 +120,17 @@ else() list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE) + + unset(_CMAKE_ADDITIONAL_AR_NAMES) + unset(_CMAKE_ADDITIONAL_RANLIB_NAMES) + unset(_CMAKE_ADDITIONAL_STRIP_NAMES) + unset(_CMAKE_ADDITIONAL_LINKER_NAMES) + unset(_CMAKE_ADDITIONAL_NM_NAMES) + unset(_CMAKE_ADDITIONAL_OBJDUMP_NAMES) + unset(_CMAKE_ADDITIONAL_OBJCOPY_NAMES) + unset(_CMAKE_ADDITIONAL_READELF_NAMES) + unset(_CMAKE_ADDITIONAL_DLLTOOL_NAMES) + unset(_CMAKE_ADDITIONAL_ADDR2LINE_NAMES) endif() if(CMAKE_PLATFORM_HAS_INSTALLNAME) -- cgit v0.12 From c856d4556b4ec28cb818ef3c7aca1e4a30e0499d Mon Sep 17 00:00:00 2001 From: Zsolt Parragi Date: Tue, 13 Aug 2019 14:29:48 +0200 Subject: bindexplib: supporting llvm bitcode formats using llvm-nm --- Source/bindexplib.cxx | 82 +++++++++++++++++++++-- Source/bindexplib.h | 5 +- Source/cmMakefileTargetGenerator.cxx | 7 ++ Source/cmNinjaNormalTargetGenerator.cxx | 8 +++ Source/cmcmd.cxx | 13 +++- Tests/Module/CheckIPOSupported-C/CMakeLists.txt | 12 +++- Tests/Module/CheckIPOSupported-C/bar.c | 4 ++ Tests/Module/CheckIPOSupported-C/main.c | 3 +- Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt | 15 ++++- Tests/Module/CheckIPOSupported-CXX/bar.cpp | 4 ++ Tests/Module/CheckIPOSupported-CXX/main.cpp | 3 +- 11 files changed, 144 insertions(+), 12 deletions(-) create mode 100644 Tests/Module/CheckIPOSupported-C/bar.c create mode 100644 Tests/Module/CheckIPOSupported-CXX/bar.cpp diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx index a107294..7e5db26 100644 --- a/Source/bindexplib.cxx +++ b/Source/bindexplib.cxx @@ -64,9 +64,12 @@ */ #include "bindexplib.h" +#include "cmSystemTools.h" #include "cmsys/Encoding.hxx" #include "cmsys/FStream.hxx" #include +#include +#include #include #ifndef IMAGE_FILE_MACHINE_ARM @@ -301,7 +304,63 @@ private: bool IsI386; }; -bool DumpFile(const char* filename, std::set& symbols, +bool DumpFileWithLlvmNm(std::string const& nmPath, const char* filename, + std::set& symbols, + std::set& dataSymbols) +{ + std::string output; + // break up command line into a vector + std::vector command; + command.push_back(nmPath); + command.push_back("--no-weak"); + command.push_back("--defined-only"); + command.push_back("--format=posix"); + command.push_back(filename); + + // run the command + int exit_code = 0; + cmSystemTools::RunSingleCommand(command, &output, &output, &exit_code, "", + cmSystemTools::OUTPUT_NONE); + + if (exit_code != 0) { + fprintf(stderr, "llvm-nm returned an error: %s\n", output.c_str()); + return false; + } + + std::istringstream ss(output); + std::string line; + while (std::getline(ss, line)) { + if (line.empty()) { // last line + continue; + } + size_t sym_end = line.find(" "); + if (sym_end == std::string::npos) { + fprintf(stderr, "Couldn't parse llvm-nm output line: %s\n", + line.c_str()); + return false; + } + if (line.size() < sym_end + 1) { + fprintf(stderr, "Couldn't parse llvm-nm output line: %s\n", + line.c_str()); + return false; + } + const std::string sym = line.substr(0, sym_end); + const char sym_type = line[sym_end + 1]; + switch (sym_type) { + case 'D': + dataSymbols.insert(sym); + break; + case 'T': + symbols.insert(sym); + break; + } + } + + return true; +} + +bool DumpFile(std::string const& nmPath, const char* filename, + std::set& symbols, std::set& dataSymbols) { HANDLE hFile; @@ -356,16 +415,26 @@ bool DumpFile(const char* filename, std::set& symbols, (imageHeader->Machine == IMAGE_FILE_MACHINE_I386)); symbolDumper.DumpObjFile(); } else { - // check for /bigobj format + // check for /bigobj and llvm LTO format cmANON_OBJECT_HEADER_BIGOBJ* h = (cmANON_OBJECT_HEADER_BIGOBJ*)lpFileBase; if (h->Sig1 == 0x0 && h->Sig2 == 0xffff) { + // bigobj DumpSymbols symbolDumper((cmANON_OBJECT_HEADER_BIGOBJ*)lpFileBase, symbols, dataSymbols, (h->Machine == IMAGE_FILE_MACHINE_I386)); symbolDumper.DumpObjFile(); + } else if ( + // BCexCODE - llvm bitcode + (h->Sig1 == 0x4342 && h->Sig2 == 0xDEC0) || + // 0x0B17C0DE - llvm bitcode BC wrapper + (h->Sig1 == 0x0B17 && h->Sig2 == 0xC0DE)) { + + return DumpFileWithLlvmNm(nmPath, filename, symbols, dataSymbols); + } else { - printf("unrecognized file format in '%s'\n", filename); + printf("unrecognized file format in '%s, %u'\n", filename, + imageHeader->Machine); return false; } } @@ -378,7 +447,7 @@ bool DumpFile(const char* filename, std::set& symbols, bool bindexplib::AddObjectFile(const char* filename) { - return DumpFile(filename, this->Symbols, this->DataSymbols); + return DumpFile(NmPath, filename, this->Symbols, this->DataSymbols); } bool bindexplib::AddDefinitionFile(const char* filename) @@ -419,3 +488,8 @@ void bindexplib::WriteFile(FILE* file) fprintf(file, "\t%s\n", s.c_str()); } } + +void bindexplib::SetNmPath(std::string const& nm) +{ + NmPath = nm; +} diff --git a/Source/bindexplib.h b/Source/bindexplib.h index 3e22ac7..6c066c5 100644 --- a/Source/bindexplib.h +++ b/Source/bindexplib.h @@ -12,13 +12,16 @@ class bindexplib { public: - bindexplib() {} + bindexplib() { NmPath = "nm"; } bool AddDefinitionFile(const char* filename); bool AddObjectFile(const char* filename); void WriteFile(FILE* file); + void SetNmPath(std::string const& nm); + private: std::set Symbols; std::set DataSymbols; + std::string NmPath; }; #endif diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index f99fe4e..f84ec76 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -15,6 +15,7 @@ #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmGlobalUnixMakefileGenerator3.h" +#include "cmLocalCommonGenerator.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmMakefileExecutableTargetGenerator.h" @@ -1738,6 +1739,12 @@ void cmMakefileTargetGenerator::GenDefFile( this->LocalGenerator->MaybeConvertToRelativePath( this->LocalGenerator->GetCurrentBinaryDirectory(), objlist_file), cmOutputConverter::SHELL); + const char* nm_executable = this->Makefile->GetDefinition("CMAKE_NM"); + if (nm_executable && *nm_executable) { + cmd += " --nm="; + cmd += this->LocalCommonGenerator->ConvertToOutputFormat( + nm_executable, cmOutputConverter::SHELL); + } real_link_commands.insert(real_link_commands.begin(), cmd); // create a list of obj files for the -E __create_def to read cmGeneratedFileStream fout(objlist_file); diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 17a5527..df4d45d 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -20,6 +20,7 @@ #include "cmGlobalNinjaGenerator.h" #include "cmLinkLineComputer.h" #include "cmLinkLineDeviceComputer.h" +#include "cmLocalCommonGenerator.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" @@ -974,6 +975,13 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string obj_list_file = mdi->DefFile + ".objs"; cmd += this->GetLocalGenerator()->ConvertToOutputFormat( obj_list_file, cmOutputConverter::SHELL); + + const char* nm_executable = GetMakefile()->GetDefinition("CMAKE_NM"); + if (nm_executable && *nm_executable) { + cmd += " --nm="; + cmd += this->LocalCommonGenerator->ConvertToOutputFormat( + nm_executable, cmOutputConverter::SHELL); + } preLinkCmdLines.push_back(std::move(cmd)); // create a list of obj files for the -E __create_def to read diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 2be8bae..08cad7d 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -558,8 +558,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args) #if defined(_WIN32) && !defined(CMAKE_BOOTSTRAP) else if (args[1] == "__create_def") { if (args.size() < 4) { - std::cerr - << "__create_def Usage: -E __create_def outfile.def objlistfile\n"; + std::cerr << "__create_def Usage: -E __create_def outfile.def " + "objlistfile [-nm=nm-path]\n"; return 1; } FILE* fout = cmsys::SystemTools::Fopen(args[2].c_str(), "w+"); @@ -576,6 +576,15 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args) } std::string file; bindexplib deffile; + if (args.size() >= 5) { + auto a = args[4]; + if (cmHasLiteralPrefix(a, "--nm=")) { + deffile.SetNmPath(a.substr(5)); + std::cerr << a.substr(5) << "\n"; + } else { + std::cerr << "unknown argument: " << a << "\n"; + } + } while (cmSystemTools::GetLineFromStream(fin, file)) { std::string const& ext = cmSystemTools::GetFilenameLastExtension(file); if (cmSystemTools::LowerCase(ext) == ".def") { diff --git a/Tests/Module/CheckIPOSupported-C/CMakeLists.txt b/Tests/Module/CheckIPOSupported-C/CMakeLists.txt index 4a41a98..c5cd03e 100644 --- a/Tests/Module/CheckIPOSupported-C/CMakeLists.txt +++ b/Tests/Module/CheckIPOSupported-C/CMakeLists.txt @@ -13,8 +13,18 @@ elseif(CMake_TEST_IPO_WORKS_C) endif() add_library(foo foo.c) +if(NOT CYGWIN AND (NOT WIN32 OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")) + add_library(bar SHARED bar.c) + if(WIN32) + # Bindexplib for clang supports LTO objects + set_target_properties(bar PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) + endif() +else() + # TODO: bindexplib doesn't support exporting IPO symbols with other compilers on Windows + add_library(bar STATIC bar.c) +endif() add_executable(CheckIPOSupported-C main.c) -target_link_libraries(CheckIPOSupported-C PUBLIC foo) +target_link_libraries(CheckIPOSupported-C PUBLIC foo bar) enable_testing() add_test(NAME CheckIPOSupported-C COMMAND CheckIPOSupported-C) diff --git a/Tests/Module/CheckIPOSupported-C/bar.c b/Tests/Module/CheckIPOSupported-C/bar.c new file mode 100644 index 0000000..680f213 --- /dev/null +++ b/Tests/Module/CheckIPOSupported-C/bar.c @@ -0,0 +1,4 @@ +int bar() +{ + return 0x42; +} diff --git a/Tests/Module/CheckIPOSupported-C/main.c b/Tests/Module/CheckIPOSupported-C/main.c index 99204ab..28ab26f 100644 --- a/Tests/Module/CheckIPOSupported-C/main.c +++ b/Tests/Module/CheckIPOSupported-C/main.c @@ -1,8 +1,9 @@ int foo(); +int bar(); int main() { - if (foo() == 0) { + if (foo() != bar()) { return 1; } return 0; diff --git a/Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt b/Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt index 1bb2b84..237bf1d 100644 --- a/Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt +++ b/Tests/Module/CheckIPOSupported-CXX/CMakeLists.txt @@ -12,9 +12,20 @@ elseif(CMake_TEST_IPO_WORKS_CXX) message(FATAL_ERROR "IPO expected to work, but the check failed:\n ${ipo_output}") endif() -add_library(foo foo.cpp) + +add_library(foo STATIC foo.cpp) +if(NOT CYGWIN AND (NOT WIN32 OR "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")) + add_library(bar SHARED bar.cpp) + if(WIN32) + # Bindexplib for clang supports LTO objects + set_target_properties(bar PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) + endif() +else() + # TODO: bindexplib doesn't support exporting IPO symbols with other compilers on Windows + add_library(bar STATIC bar.cpp) +endif() add_executable(CheckIPOSupported-CXX main.cpp) -target_link_libraries(CheckIPOSupported-CXX PUBLIC foo) +target_link_libraries(CheckIPOSupported-CXX PUBLIC foo bar) enable_testing() add_test(NAME CheckIPOSupported-CXX COMMAND CheckIPOSupported-CXX) diff --git a/Tests/Module/CheckIPOSupported-CXX/bar.cpp b/Tests/Module/CheckIPOSupported-CXX/bar.cpp new file mode 100644 index 0000000..680f213 --- /dev/null +++ b/Tests/Module/CheckIPOSupported-CXX/bar.cpp @@ -0,0 +1,4 @@ +int bar() +{ + return 0x42; +} diff --git a/Tests/Module/CheckIPOSupported-CXX/main.cpp b/Tests/Module/CheckIPOSupported-CXX/main.cpp index 99204ab..28ab26f 100644 --- a/Tests/Module/CheckIPOSupported-CXX/main.cpp +++ b/Tests/Module/CheckIPOSupported-CXX/main.cpp @@ -1,8 +1,9 @@ int foo(); +int bar(); int main() { - if (foo() == 0) { + if (foo() != bar()) { return 1; } return 0; -- cgit v0.12 From dca9c33abc7ce6b041b378e1ebc43c35327027b3 Mon Sep 17 00:00:00 2001 From: Zsolt Parragi Date: Thu, 29 Aug 2019 11:52:18 +0200 Subject: Tests: Remove old IPO test This test didn't really result in IPO compilation, there are other better tests for this. --- Tests/CMakeLists.txt | 1 - Tests/IPO/CMakeLists.txt | 7 ------- 2 files changed, 8 deletions(-) delete mode 100644 Tests/IPO/CMakeLists.txt diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 34858b8..03d7a7e 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -416,7 +416,6 @@ if(BUILD_TESTING) ADD_TEST_MACRO(COnly COnly) ADD_TEST_MACRO(CxxOnly CxxOnly) ADD_TEST_MACRO(CxxSubdirC CxxSubdirC) - ADD_TEST_MACRO(IPO COnly/COnly) ADD_TEST_MACRO(OutDir runtime/OutDir) ADD_TEST_MACRO(OutName exe.OutName.exe) ADD_TEST_MACRO(ObjectLibrary UseCshared) diff --git a/Tests/IPO/CMakeLists.txt b/Tests/IPO/CMakeLists.txt deleted file mode 100644 index 6dabf86..0000000 --- a/Tests/IPO/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required (VERSION 2.8) -project(IPO NONE) - -set_property(DIRECTORY PROPERTY INTERPROCEDURAL_OPTIMIZATION 1) - -add_subdirectory(../COnly COnly) -add_subdirectory(../CxxOnly CxxOnly) -- cgit v0.12