From b6071c93f556a2ee1ad30eae0f3a1dbbb5b5a1d7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 1 Feb 2021 13:29:51 -0500 Subject: Rename CMAKE_USE_ELF_PARSER to CMake_USE_ELF_PARSER We use the `CMake_` prefix for options affecting CMake itself. --- Source/CMakeLists.txt | 10 +++++----- Source/cmConfigure.cmake.h.in | 2 +- Source/cmELF.h | 4 ++-- Source/cmFileCommand.cxx | 4 ++-- Source/cmGeneratorTarget.cxx | 2 +- Source/cmSystemTools.cxx | 14 +++++++------- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index b3d8369..c2e1ed3 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -19,7 +19,7 @@ else() CHECK_INCLUDE_FILE("elf.h" HAVE_ELF_H) endif() if(HAVE_ELF_H) - set(CMAKE_USE_ELF_PARSER 1) + set(CMake_USE_ELF_PARSER 1) elseif(HAIKU) # On Haiku, we need to include elf32.h from the private headers set(CMake_HAIKU_INCLUDE_DIRS @@ -32,13 +32,13 @@ elseif(HAIKU) unset(CMAKE_REQUIRED_INCLUDES) if(HAVE_ELF32_H) - set(CMAKE_USE_ELF_PARSER 1) + set(CMake_USE_ELF_PARSER 1) else() unset(CMake_HAIKU_INCLUDE_DIRS) - set(CMAKE_USE_ELF_PARSER) + set(CMake_USE_ELF_PARSER) endif() else() - set(CMAKE_USE_ELF_PARSER) + set(CMake_USE_ELF_PARSER) endif() if(NOT CMake_DEFAULT_RECURSION_LIMIT) @@ -108,7 +108,7 @@ include_directories( ) # Check if we can build the ELF parser. -if(CMAKE_USE_ELF_PARSER) +if(CMake_USE_ELF_PARSER) set(ELF_SRCS cmELF.h cmELF.cxx) endif() diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index cf32b05..9b785b9 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -16,7 +16,7 @@ #cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE #cmakedefine HAVE_UNSETENV -#cmakedefine CMAKE_USE_ELF_PARSER +#cmakedefine CMake_USE_ELF_PARSER #cmakedefine CMAKE_USE_MACH_PARSER #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@ #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" diff --git a/Source/cmELF.h b/Source/cmELF.h index 99eb4f4..c479e2b 100644 --- a/Source/cmELF.h +++ b/Source/cmELF.h @@ -10,8 +10,8 @@ #include #include -#if !defined(CMAKE_USE_ELF_PARSER) -# error "This file may be included only if CMAKE_USE_ELF_PARSER is enabled." +#if !defined(CMake_USE_ELF_PARSER) +# error "This file may be included only if CMake_USE_ELF_PARSER is enabled." #endif class cmELFInternal; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 031e0d7..f674833 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -64,7 +64,7 @@ # include "cmFileLockResult.h" #endif -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) # include "cmELF.h" #endif @@ -1198,7 +1198,7 @@ bool HandleReadElfCommand(std::vector const& args, return false; } -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) cmELF elf(fileNameArg.c_str()); if (!arguments.RPath.empty()) { diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index aaefe9c..9a70b16 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -2059,7 +2059,7 @@ bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const return true; } -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) // Enable if the rpath flag uses a separator and the target uses ELF // binaries. std::string ll = this->GetLinkerLanguage(config); diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 18c266f..95e2a35 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -45,7 +45,7 @@ # include "cmCryptoHash.h" #endif -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) # include "cmELF.h" #endif @@ -2317,7 +2317,7 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath, { // For ELF shared libraries use a real parser to get the correct // soname. -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) cmELF elf(fullPath.c_str()); if (elf) { return elf.GetSOName(soname); @@ -2360,7 +2360,7 @@ bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath, return false; } -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) std::string::size_type cmSystemToolsFindRPath(std::string const& have, std::string const& want) { @@ -2394,7 +2394,7 @@ std::string::size_type cmSystemToolsFindRPath(std::string const& have, } #endif -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) struct cmSystemToolsRPathInfo { unsigned long Position; @@ -2404,7 +2404,7 @@ struct cmSystemToolsRPathInfo }; #endif -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) bool cmSystemTools::ChangeRPath(std::string const& file, std::string const& oldRPath, std::string const& newRPath, @@ -2720,7 +2720,7 @@ int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs) return cm_strverscmp(lhs.c_str(), rhs.c_str()); } -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, bool* removed) { @@ -2872,7 +2872,7 @@ bool cmSystemTools::RemoveRPath(std::string const& /*file*/, bool cmSystemTools::CheckRPath(std::string const& file, std::string const& newRPath) { -#if defined(CMAKE_USE_ELF_PARSER) +#if defined(CMake_USE_ELF_PARSER) // Parse the ELF binary. cmELF elf(file.c_str()); -- cgit v0.12 From cdcfe3eb99f2471740dccdbbef5c47414c15e661 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 1 Feb 2021 13:31:02 -0500 Subject: Rename CMAKE_USE_MACH_PARSER to CMake_USE_MACH_PARSER We use the `CMake_` prefix for options affecting CMake itself. --- Source/CMakeLists.txt | 4 ++-- Source/cmConfigure.cmake.h.in | 2 +- Source/cmMachO.h | 4 ++-- Source/cmSystemTools.cxx | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c2e1ed3..26aaa79 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -54,7 +54,7 @@ if(NOT CMake_DEFAULT_RECURSION_LIMIT) endif() if(APPLE) - set(CMAKE_USE_MACH_PARSER 1) + set(CMake_USE_MACH_PARSER 1) endif() set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR}) @@ -113,7 +113,7 @@ if(CMake_USE_ELF_PARSER) endif() # Check if we can build the Mach-O parser. -if(CMAKE_USE_MACH_PARSER) +if(CMake_USE_MACH_PARSER) set(MACH_SRCS cmMachO.h cmMachO.cxx) endif() diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 9b785b9..2fef246 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -17,7 +17,7 @@ #cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE #cmakedefine HAVE_UNSETENV #cmakedefine CMake_USE_ELF_PARSER -#cmakedefine CMAKE_USE_MACH_PARSER +#cmakedefine CMake_USE_MACH_PARSER #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@ #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@" diff --git a/Source/cmMachO.h b/Source/cmMachO.h index be92c95..faa024b 100644 --- a/Source/cmMachO.h +++ b/Source/cmMachO.h @@ -7,8 +7,8 @@ #include #include -#if !defined(CMAKE_USE_MACH_PARSER) -# error "This file may be included only if CMAKE_USE_MACH_PARSER is enabled." +#if !defined(CMake_USE_MACH_PARSER) +# error "This file may be included only if CMake_USE_MACH_PARSER is enabled." #endif class cmMachOInternal; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 95e2a35..8c5a657 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -49,7 +49,7 @@ # include "cmELF.h" #endif -#if defined(CMAKE_USE_MACH_PARSER) +#if defined(CMake_USE_MACH_PARSER) # include "cmMachO.h" #endif @@ -2347,7 +2347,7 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath, bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath, std::string& soname) { -#if defined(CMAKE_USE_MACH_PARSER) +#if defined(CMake_USE_MACH_PARSER) cmMachO macho(fullPath.c_str()); if (macho) { return macho.GetInstallName(soname); -- cgit v0.12 From d8f3e68ca948ae25e923dd944b07ea4670645232 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 2 Feb 2021 19:15:06 -0500 Subject: Ninja Multi-Config: Enable relink diagnostic message We already have a message for the "Ninja" generator, but it applies to the "Ninja Multi-Config" generator too. --- Source/cmGeneratorTarget.cxx | 3 +-- Source/cmGlobalGenerator.h | 2 ++ Source/cmGlobalNinjaGenerator.h | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 9a70b16..0171d8a 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -2003,8 +2003,7 @@ bool cmGeneratorTarget::NeedRelinkBeforeInstall( // this target must be relinked. bool have_rpath = this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(config); - bool is_ninja = - this->LocalGenerator->GetGlobalGenerator()->GetName() == "Ninja"; + bool is_ninja = this->LocalGenerator->GetGlobalGenerator()->IsNinja(); if (have_rpath && is_ninja) { std::ostringstream w; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 86fb228..590de26 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -438,6 +438,8 @@ public: virtual bool IsVisualStudio() const { return false; } + virtual bool IsNinja() const { return false; } + /** Return true if we know the exact location of object files. If false, store the reason in the given string. This is meaningful only after EnableLanguage has been called. */ diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 78fcb49..0c919ef 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -170,6 +170,8 @@ public: static std::string GetActualName() { return "Ninja"; } + bool IsNinja() const override { return true; } + /** Get encoding used by generator for ninja files */ codecvt::Encoding GetMakefileEncoding() const override; -- cgit v0.12 From f79d991dfd607a6444fe5636fc264cc204fcb2ea Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 2 Feb 2021 19:10:52 -0500 Subject: Tests: Convert CMake.ELF to RunCMake.file-RPATH ELF case --- Tests/CMakeTests/CMakeLists.txt | 4 -- Tests/CMakeTests/ELF/elf32lsb.bin | Bin 2824 -> 0 bytes Tests/CMakeTests/ELF/elf32msb.bin | Bin 17984 -> 0 bytes Tests/CMakeTests/ELF/elf64lsb.bin | Bin 4320 -> 0 bytes Tests/CMakeTests/ELF/elf64msb.bin | Bin 18704 -> 0 bytes Tests/CMakeTests/ELFTest.cmake.in | 73 --------------------------- Tests/RunCMake/CMakeLists.txt | 3 ++ Tests/RunCMake/file-RPATH/Common.cmake | 64 +++++++++++++++++++++++ Tests/RunCMake/file-RPATH/ELF.cmake | 9 ++++ Tests/RunCMake/file-RPATH/ELF/elf32lsb.bin | Bin 0 -> 2824 bytes Tests/RunCMake/file-RPATH/ELF/elf32msb.bin | Bin 0 -> 17984 bytes Tests/RunCMake/file-RPATH/ELF/elf64lsb.bin | Bin 0 -> 4320 bytes Tests/RunCMake/file-RPATH/ELF/elf64msb.bin | Bin 0 -> 18704 bytes Tests/RunCMake/file-RPATH/RunCMakeTest.cmake | 5 ++ 14 files changed, 81 insertions(+), 77 deletions(-) delete mode 100644 Tests/CMakeTests/ELF/elf32lsb.bin delete mode 100644 Tests/CMakeTests/ELF/elf32msb.bin delete mode 100644 Tests/CMakeTests/ELF/elf64lsb.bin delete mode 100644 Tests/CMakeTests/ELF/elf64msb.bin delete mode 100644 Tests/CMakeTests/ELFTest.cmake.in create mode 100644 Tests/RunCMake/file-RPATH/Common.cmake create mode 100644 Tests/RunCMake/file-RPATH/ELF.cmake create mode 100755 Tests/RunCMake/file-RPATH/ELF/elf32lsb.bin create mode 100755 Tests/RunCMake/file-RPATH/ELF/elf32msb.bin create mode 100755 Tests/RunCMake/file-RPATH/ELF/elf64lsb.bin create mode 100755 Tests/RunCMake/file-RPATH/ELF/elf64msb.bin create mode 100644 Tests/RunCMake/file-RPATH/RunCMakeTest.cmake diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt index 348e6d0..6bbbe7d 100644 --- a/Tests/CMakeTests/CMakeLists.txt +++ b/Tests/CMakeTests/CMakeLists.txt @@ -44,10 +44,6 @@ set_property(TEST CMake.FileDownloadBadHash PROPERTY AddCMakeTest(FileUpload "") -if(HAVE_ELF_H) - AddCMakeTest(ELF "") -endif() - set(EndStuff_PreArgs "-Ddir:STRING=${CMAKE_CURRENT_BINARY_DIR}/EndStuffTest" ) diff --git a/Tests/CMakeTests/ELF/elf32lsb.bin b/Tests/CMakeTests/ELF/elf32lsb.bin deleted file mode 100644 index 803ac43..0000000 Binary files a/Tests/CMakeTests/ELF/elf32lsb.bin and /dev/null differ diff --git a/Tests/CMakeTests/ELF/elf32msb.bin b/Tests/CMakeTests/ELF/elf32msb.bin deleted file mode 100644 index d04aaf7..0000000 Binary files a/Tests/CMakeTests/ELF/elf32msb.bin and /dev/null differ diff --git a/Tests/CMakeTests/ELF/elf64lsb.bin b/Tests/CMakeTests/ELF/elf64lsb.bin deleted file mode 100644 index a21e3ea..0000000 Binary files a/Tests/CMakeTests/ELF/elf64lsb.bin and /dev/null differ diff --git a/Tests/CMakeTests/ELF/elf64msb.bin b/Tests/CMakeTests/ELF/elf64msb.bin deleted file mode 100644 index bbe2551..0000000 Binary files a/Tests/CMakeTests/ELF/elf64msb.bin and /dev/null differ diff --git a/Tests/CMakeTests/ELFTest.cmake.in b/Tests/CMakeTests/ELFTest.cmake.in deleted file mode 100644 index 85c2360..0000000 --- a/Tests/CMakeTests/ELFTest.cmake.in +++ /dev/null @@ -1,73 +0,0 @@ -set(names - elf32lsb.bin - elf32msb.bin - elf64lsb.bin - elf64msb.bin - ) - -# Prepare binaries on which to operate. -set(in "@CMAKE_CURRENT_SOURCE_DIR@/ELF") -set(out "@CMAKE_CURRENT_BINARY_DIR@/ELF-Out") -file(REMOVE_RECURSE "${out}") -file(MAKE_DIRECTORY "${out}") -foreach(f ${names}) - file(COPY ${in}/${f} DESTINATION ${out} NO_SOURCE_PERMISSIONS) - list(APPEND files "${out}/${f}") -endforeach() - -foreach(f ${files}) - # Check for the initial RPATH. - file(RPATH_CHECK FILE "${f}" RPATH "/sample/rpath") - if(NOT EXISTS "${f}") - message(FATAL_ERROR "RPATH_CHECK removed ${f}") - endif() - - # Change the RPATH. - file(RPATH_CHANGE FILE "${f}" - OLD_RPATH "/sample/rpath" - NEW_RPATH "/path1:/path2") - set(rpath) - file(STRINGS "${f}" rpath REGEX "/path1:/path2" LIMIT_COUNT 1) - if(NOT rpath) - message(FATAL_ERROR "RPATH not changed in ${f}") - endif() - - # Change the RPATH without compiler defined rpath removed - file(RPATH_CHANGE FILE "${f}" - OLD_RPATH "/path2" - NEW_RPATH "/path3") - set(rpath) - file(STRINGS "${f}" rpath REGEX "/path1:/path3" LIMIT_COUNT 1) - if(NOT rpath) - message(FATAL_ERROR "RPATH not updated in ${f}") - endif() - - # Change the RPATH with compiler defined rpath removed - file(RPATH_CHANGE FILE "${f}" - OLD_RPATH "/path3" - NEW_RPATH "/rpath/sample" - INSTALL_REMOVE_ENVIRONMENT_RPATH) - set(rpath) - file(STRINGS "${f}" rpath REGEX "/rpath/sample" LIMIT_COUNT 1) - if(NOT rpath) - message(FATAL_ERROR "RPATH not updated in ${f}") - endif() - file(STRINGS "${f}" rpath REGEX "/path1" LIMIT_COUNT 1) - if(rpath) - message(FATAL_ERROR "RPATH not removed in ${f}") - endif() - - # Remove the RPATH. - file(RPATH_REMOVE FILE "${f}") - set(rpath) - file(STRINGS "${f}" rpath REGEX "/rpath/sample" LIMIT_COUNT 1) - if(rpath) - message(FATAL_ERROR "RPATH not removed from ${f}") - endif() - - # Check again...this should remove the file. - file(RPATH_CHECK FILE "${f}" RPATH "/sample/rpath") - if(EXISTS "${f}") - message(FATAL_ERROR "RPATH_CHECK did not remove ${f}") - endif() -endforeach() diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index f58e2f3..e0804d7 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -358,6 +358,9 @@ add_RunCMake_test(ctest_upload) add_RunCMake_test(ctest_fixtures) add_RunCMake_test(file) add_RunCMake_test(file-CHMOD) +if(HAVE_ELF_H) + add_RunCMake_test(file-RPATH -DHAVE_ELF_H=${HAVE_ELF_H}) +endif() add_RunCMake_test(find_file) add_RunCMake_test(find_library -DCYGWIN=${CYGWIN}) add_RunCMake_test(find_package) diff --git a/Tests/RunCMake/file-RPATH/Common.cmake b/Tests/RunCMake/file-RPATH/Common.cmake new file mode 100644 index 0000000..cc1efb5 --- /dev/null +++ b/Tests/RunCMake/file-RPATH/Common.cmake @@ -0,0 +1,64 @@ +# Prepare binaries on which to operate. +set(in "${CMAKE_CURRENT_LIST_DIR}/${format}") +set(out "${CMAKE_CURRENT_BINARY_DIR}") +foreach(f ${names}) + file(COPY ${in}/${f} DESTINATION ${out} NO_SOURCE_PERMISSIONS) + list(APPEND files "${out}/${f}") +endforeach() + +foreach(f ${files}) + # Check for the initial RPATH. + file(RPATH_CHECK FILE "${f}" RPATH "/sample/rpath") + if(NOT EXISTS "${f}") + message(FATAL_ERROR "RPATH_CHECK removed ${f}") + endif() + + # Change the RPATH. + file(RPATH_CHANGE FILE "${f}" + OLD_RPATH "/sample/rpath" + NEW_RPATH "/path1:/path2") + set(rpath) + file(STRINGS "${f}" rpath REGEX "/path1:/path2" LIMIT_COUNT 1) + if(NOT rpath) + message(FATAL_ERROR "RPATH not changed in ${f}") + endif() + + # Change the RPATH without compiler defined rpath removed + file(RPATH_CHANGE FILE "${f}" + OLD_RPATH "/path2" + NEW_RPATH "/path3") + set(rpath) + file(STRINGS "${f}" rpath REGEX "/path1:/path3" LIMIT_COUNT 1) + if(NOT rpath) + message(FATAL_ERROR "RPATH not updated in ${f}") + endif() + + # Change the RPATH with compiler defined rpath removed + file(RPATH_CHANGE FILE "${f}" + OLD_RPATH "/path3" + NEW_RPATH "/rpath/sample" + INSTALL_REMOVE_ENVIRONMENT_RPATH) + set(rpath) + file(STRINGS "${f}" rpath REGEX "/rpath/sample" LIMIT_COUNT 1) + if(NOT rpath) + message(FATAL_ERROR "RPATH not updated in ${f}") + endif() + file(STRINGS "${f}" rpath REGEX "/path1" LIMIT_COUNT 1) + if(rpath) + message(FATAL_ERROR "RPATH not removed in ${f}") + endif() + + # Remove the RPATH. + file(RPATH_REMOVE FILE "${f}") + set(rpath) + file(STRINGS "${f}" rpath REGEX "/rpath/sample" LIMIT_COUNT 1) + if(rpath) + message(FATAL_ERROR "RPATH not removed from ${f}") + endif() + + # Check again...this should remove the file. + file(RPATH_CHECK FILE "${f}" RPATH "/sample/rpath") + if(EXISTS "${f}") + message(FATAL_ERROR "RPATH_CHECK did not remove ${f}") + endif() +endforeach() diff --git a/Tests/RunCMake/file-RPATH/ELF.cmake b/Tests/RunCMake/file-RPATH/ELF.cmake new file mode 100644 index 0000000..558b2e2 --- /dev/null +++ b/Tests/RunCMake/file-RPATH/ELF.cmake @@ -0,0 +1,9 @@ +set(names + elf32lsb.bin + elf32msb.bin + elf64lsb.bin + elf64msb.bin + ) +set(format ELF) + +include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake) diff --git a/Tests/RunCMake/file-RPATH/ELF/elf32lsb.bin b/Tests/RunCMake/file-RPATH/ELF/elf32lsb.bin new file mode 100755 index 0000000..803ac43 Binary files /dev/null and b/Tests/RunCMake/file-RPATH/ELF/elf32lsb.bin differ diff --git a/Tests/RunCMake/file-RPATH/ELF/elf32msb.bin b/Tests/RunCMake/file-RPATH/ELF/elf32msb.bin new file mode 100755 index 0000000..d04aaf7 Binary files /dev/null and b/Tests/RunCMake/file-RPATH/ELF/elf32msb.bin differ diff --git a/Tests/RunCMake/file-RPATH/ELF/elf64lsb.bin b/Tests/RunCMake/file-RPATH/ELF/elf64lsb.bin new file mode 100755 index 0000000..a21e3ea Binary files /dev/null and b/Tests/RunCMake/file-RPATH/ELF/elf64lsb.bin differ diff --git a/Tests/RunCMake/file-RPATH/ELF/elf64msb.bin b/Tests/RunCMake/file-RPATH/ELF/elf64msb.bin new file mode 100755 index 0000000..bbe2551 Binary files /dev/null and b/Tests/RunCMake/file-RPATH/ELF/elf64msb.bin differ diff --git a/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake b/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake new file mode 100644 index 0000000..11e90bb --- /dev/null +++ b/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +if(HAVE_ELF_H) + run_cmake_command(ELF ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/ELF.cmake) +endif() -- cgit v0.12 From 69e1d95a8a6c75f7a1be1259fefe938265cbf4dc Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 2 Feb 2021 15:54:33 -0500 Subject: Tests: Add sample XCOFF binaries Generate the binaries as follows: $ cat main.c int main(void) { return 0; } $ xlc -q64 -o xcoff64.bin -Wl,-blibpath:/sample/rpath:/usr/lib:/lib main.c $ strip -X 64 xcoff64.bin $ xlc -q32 -o xcoff32.bin -Wl,-blibpath:/sample/rpath:/usr/lib:/lib main.c $ strip -X 32 xcoff32.bin --- Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin | Bin 0 -> 1706 bytes Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin | Bin 0 -> 2291 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin create mode 100644 Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin diff --git a/Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin b/Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin new file mode 100644 index 0000000..2d8d961 Binary files /dev/null and b/Tests/RunCMake/file-RPATH/XCOFF/xcoff32.bin differ diff --git a/Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin b/Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin new file mode 100644 index 0000000..bb5f5a7 Binary files /dev/null and b/Tests/RunCMake/file-RPATH/XCOFF/xcoff64.bin differ -- cgit v0.12 From ddaaee907dc617f6a763de37c368e50cd23a8a53 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 29 Jan 2021 18:00:19 +0000 Subject: CMakeDetermineCompilerId: Recognize XCOFF executable format --- Modules/CMakeDetermineCompilerId.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index 90697f0..1be570e 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -920,6 +920,11 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file) set(CMAKE_EXECUTABLE_FORMAT "MACHO" CACHE INTERNAL "Executable file format") endif() + # XCOFF files start with 0x01 followed by 0xDF (32-bit) or 0xF7 (64-bit). + if("${CMAKE_EXECUTABLE_MAGIC}" MATCHES "^01(df|f7)") + set(CMAKE_EXECUTABLE_FORMAT "XCOFF" CACHE INTERNAL "Executable file format") + endif() + endif() if(NOT DEFINED CMAKE_EXECUTABLE_FORMAT) set(CMAKE_EXECUTABLE_FORMAT) -- cgit v0.12 From 56fc4a325f08465b725b08b3975cd51bdd2305c8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 29 Jan 2021 13:25:51 -0500 Subject: cmXCOFF: Add helper to parse and edit the XCOFF binary format --- Source/CMakeLists.txt | 10 ++ Source/cmConfigure.cmake.h.in | 1 + Source/cmXCOFF.cxx | 356 ++++++++++++++++++++++++++++++++++++++++++ Source/cmXCOFF.h | 65 ++++++++ 4 files changed, 432 insertions(+) create mode 100644 Source/cmXCOFF.cxx create mode 100644 Source/cmXCOFF.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 26aaa79..6adc9cf 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -57,6 +57,10 @@ if(APPLE) set(CMake_USE_MACH_PARSER 1) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "AIX") + set(CMake_USE_XCOFF_PARSER 1) +endif() + set(EXECUTABLE_OUTPUT_PATH ${CMake_BIN_DIR}) if(WIN32) @@ -117,6 +121,11 @@ if(CMake_USE_MACH_PARSER) set(MACH_SRCS cmMachO.h cmMachO.cxx) endif() +# Check if we can build the XCOFF parser. +if(CMake_USE_XCOFF_PARSER) + set(XCOFF_SRCS cmXCOFF.h cmXCOFF.cxx) +endif() + # # Sources for CMakeLib # @@ -465,6 +474,7 @@ set(SRCS cmWorkerPool.h cmWorkingDirectory.cxx cmWorkingDirectory.h + ${XCOFF_SRCS} cmXMLParser.cxx cmXMLParser.h cmXMLSafe.cxx diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 2fef246..aeca6b4 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -18,6 +18,7 @@ #cmakedefine HAVE_UNSETENV #cmakedefine CMake_USE_ELF_PARSER #cmakedefine CMake_USE_MACH_PARSER +#cmakedefine CMake_USE_XCOFF_PARSER #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@ #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@" diff --git a/Source/cmXCOFF.cxx b/Source/cmXCOFF.cxx new file mode 100644 index 0000000..890636e --- /dev/null +++ b/Source/cmXCOFF.cxx @@ -0,0 +1,356 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmXCOFF.h" + +#include +#include + +#include + +#include "cmsys/FStream.hxx" + +#include "cmStringAlgorithms.h" + +// Include the XCOFF format information system header. +#ifdef _AIX +# define __XCOFF32__ +# define __XCOFF64__ +# include +#else +# error "This source may be compiled only on AIX." +#endif + +class cmXCOFFInternal +{ +public: + // Construct and take ownership of the file stream object. + cmXCOFFInternal(cmXCOFF* external, std::unique_ptr fin, + cmXCOFF::Mode mode) + : External(external) + , Stream(std::move(fin)) + , Mode(mode) + { + } + + // Destruct and delete the file stream object. + virtual ~cmXCOFFInternal() = default; + + cmXCOFF::Mode GetMode() const { return this->Mode; } + + virtual cm::optional GetLibPath() = 0; + + virtual bool SetLibPath(cm::string_view libPath) = 0; + virtual bool RemoveLibPath() = 0; + +protected: + // Data common to all ELF class implementations. + + // The external cmXCOFF object. + cmXCOFF* External; + + // The stream from which to read. + std::unique_ptr Stream; + + cmXCOFF::Mode Mode; + + // Helper methods for subclasses. + void SetErrorMessage(const char* msg) { this->External->ErrorMessage = msg; } +}; + +namespace { + +struct XCOFF32 +{ + typedef struct filehdr filehdr; + typedef struct aouthdr aouthdr; + typedef struct scnhdr scnhdr; + typedef struct ldhdr ldhdr; + static const std::size_t aouthdr_size = _AOUTHSZ_EXEC; +}; +const unsigned char xcoff32_magic[] = { 0x01, 0xDF }; + +struct XCOFF64 +{ + typedef struct filehdr_64 filehdr; + typedef struct aouthdr_64 aouthdr; + typedef struct scnhdr_64 scnhdr; + typedef struct ldhdr_64 ldhdr; + static const std::size_t aouthdr_size = _AOUTHSZ_EXEC_64; +}; +const unsigned char xcoff64_magic[] = { 0x01, 0xF7 }; + +template +class Impl : public cmXCOFFInternal +{ + static_assert(sizeof(typename XCOFF::aouthdr) == XCOFF::aouthdr_size, + "aouthdr structure size matches _AOUTHSZ_EXEC macro"); + + typename XCOFF::filehdr FileHeader; + typename XCOFF::aouthdr AuxHeader; + typename XCOFF::scnhdr LoaderSectionHeader; + typename XCOFF::ldhdr LoaderHeader; + + std::streamoff LoaderImportFileTablePos = 0; + std::vector LoaderImportFileTable; + + bool Read(typename XCOFF::filehdr& x) + { + // FIXME: Add byte swapping if needed. + return static_cast( + this->Stream->read(reinterpret_cast(&x), sizeof(x))); + } + + bool Read(typename XCOFF::aouthdr& x) + { + // FIXME: Add byte swapping if needed. + return static_cast( + this->Stream->read(reinterpret_cast(&x), sizeof(x))); + } + + bool Read(typename XCOFF::scnhdr& x) + { + // FIXME: Add byte swapping if needed. + return static_cast( + this->Stream->read(reinterpret_cast(&x), sizeof(x))); + } + + bool Read(typename XCOFF::ldhdr& x) + { + // FIXME: Add byte swapping if needed. + return static_cast( + this->Stream->read(reinterpret_cast(&x), sizeof(x))); + } + + bool WriteLoaderImportFileTableLength(decltype(XCOFF::ldhdr::l_istlen) x) + { + // FIXME: Add byte swapping if needed. + return static_cast( + this->Stream->write(reinterpret_cast(&x), sizeof(x))); + } + +public: + Impl(cmXCOFF* external, std::unique_ptr fin, + cmXCOFF::Mode mode); + + cm::optional GetLibPath() override; + bool SetLibPath(cm::string_view libPath) override; + bool RemoveLibPath() override; +}; + +template +Impl::Impl(cmXCOFF* external, std::unique_ptr fin, + cmXCOFF::Mode mode) + : cmXCOFFInternal(external, std::move(fin), mode) +{ + if (!this->Read(this->FileHeader)) { + this->SetErrorMessage("Failed to read XCOFF file header."); + return; + } + if (this->FileHeader.f_opthdr != XCOFF::aouthdr_size) { + this->SetErrorMessage("XCOFF auxiliary header missing."); + return; + } + if (!this->Read(this->AuxHeader)) { + this->SetErrorMessage("Failed to read XCOFF auxiliary header."); + return; + } + if (this->AuxHeader.o_snloader == 0) { + this->SetErrorMessage("XCOFF loader section missing."); + return; + } + if (!this->Stream->seekg((this->AuxHeader.o_snloader - 1) * + sizeof(typename XCOFF::scnhdr), + std::ios::cur)) { + this->SetErrorMessage("Failed to seek to XCOFF loader section header."); + return; + } + if (!this->Read(this->LoaderSectionHeader)) { + this->SetErrorMessage("Failed to read XCOFF loader section header."); + return; + } + if ((this->LoaderSectionHeader.s_flags & STYP_LOADER) == 0) { + this->SetErrorMessage("XCOFF loader section header missing STYP_LOADER."); + return; + } + if (!this->Stream->seekg(this->LoaderSectionHeader.s_scnptr, + std::ios::beg)) { + this->SetErrorMessage("Failed to seek to XCOFF loader header."); + return; + } + if (!this->Read(this->LoaderHeader)) { + this->SetErrorMessage("Failed to read XCOFF loader header."); + return; + } + this->LoaderImportFileTablePos = + this->LoaderSectionHeader.s_scnptr + this->LoaderHeader.l_impoff; + if (!this->Stream->seekg(this->LoaderImportFileTablePos)) { + this->SetErrorMessage( + "Failed to seek to XCOFF loader import file id table."); + return; + } + this->LoaderImportFileTable.resize(this->LoaderHeader.l_istlen); + if (!this->Stream->read(this->LoaderImportFileTable.data(), + this->LoaderImportFileTable.size())) { + this->SetErrorMessage("Failed to read XCOFF loader import file id table."); + return; + } +} + +template +cm::optional Impl::GetLibPath() +{ + cm::optional result; + auto end = std::find(this->LoaderImportFileTable.begin(), + this->LoaderImportFileTable.end(), '\0'); + if (end != this->LoaderImportFileTable.end()) { + result = cm::string_view(this->LoaderImportFileTable.data(), + end - this->LoaderImportFileTable.begin()); + } + return result; +} + +template +bool Impl::SetLibPath(cm::string_view libPath) +{ + // The new LIBPATH must end in the standard AIX LIBPATH. +#define CM_AIX_LIBPATH "/usr/lib:/lib" + std::string libPathBuf; + if (libPath != CM_AIX_LIBPATH && + !cmHasLiteralSuffix(libPath, ":" CM_AIX_LIBPATH)) { + libPathBuf = std::string(libPath); + if (!libPathBuf.empty() && libPathBuf.back() != ':') { + libPathBuf.push_back(':'); + } + libPathBuf += CM_AIX_LIBPATH; + libPath = libPathBuf; + } +#undef CM_AIX_LIBPATH + + auto oldEnd = std::find(this->LoaderImportFileTable.begin(), + this->LoaderImportFileTable.end(), '\0'); + if (oldEnd == this->LoaderImportFileTable.end()) { + this->SetErrorMessage("XCOFF loader import file id table is invalid."); + return false; + } + if ((this->LoaderImportFileTable.begin() + libPath.size()) > oldEnd) { + this->SetErrorMessage("XCOFF loader import file id table is too small."); + return false; + } + + { + std::vector ift; + ift.reserve(this->LoaderImportFileTable.size()); + // Start with the new LIBPATH. + ift.insert(ift.end(), libPath.begin(), libPath.end()); + // Add the rest of the original table. + ift.insert(ift.end(), oldEnd, this->LoaderImportFileTable.end()); + // If the new table is shorter, zero out the leftover space. + ift.resize(this->LoaderImportFileTable.size(), 0); + this->LoaderHeader.l_istlen = + static_cast(ift.size()); + this->LoaderImportFileTable = std::move(ift); + } + + if (!this->Stream->seekp(this->LoaderSectionHeader.s_scnptr + + offsetof(typename XCOFF::ldhdr, l_istlen), + std::ios::beg)) { + this->SetErrorMessage( + "Failed to seek to XCOFF loader header import file id table length."); + return false; + } + if (!this->WriteLoaderImportFileTableLength(this->LoaderHeader.l_istlen)) { + this->SetErrorMessage( + "Failed to write XCOFF loader header import file id table length."); + return false; + } + if (!this->Stream->seekp(this->LoaderImportFileTablePos, std::ios::beg)) { + this->SetErrorMessage( + "Failed to seek to XCOFF loader import file id table."); + return false; + } + if (!this->Stream->write(this->LoaderImportFileTable.data(), + this->LoaderImportFileTable.size())) { + this->SetErrorMessage( + "Failed to write XCOFF loader import file id table."); + return false; + } + + return true; +} + +template +bool Impl::RemoveLibPath() +{ + return this->SetLibPath({}); +} +} + +//============================================================================ +// External class implementation. + +cmXCOFF::cmXCOFF(const char* fname, Mode mode) +{ + // Try to open the file. + std::ios::openmode fmode = std::ios::in | std::ios::binary; + if (mode == Mode::ReadWrite) { + fmode |= std::ios::out; + } + auto f = cm::make_unique(fname, fmode); + + // Quit now if the file could not be opened. + if (!f || !*f) { + this->ErrorMessage = "Error opening input file."; + return; + } + + // Read the XCOFF magic number. + unsigned char magic[2]; + if (!f->read(reinterpret_cast(magic), sizeof(magic))) { + this->ErrorMessage = "Error reading XCOFF magic number."; + return; + } + if (!f->seekg(0)) { + this->ErrorMessage = "Error seeking to beginning of file."; + return; + } + + // Check the XCOFF type. + if (magic[0] == xcoff32_magic[0] && magic[1] == xcoff32_magic[1]) { + this->Internal = cm::make_unique>(this, std::move(f), mode); + } else if (magic[0] == xcoff64_magic[0] && magic[1] == xcoff64_magic[1]) { + this->Internal = cm::make_unique>(this, std::move(f), mode); + } else { + this->ErrorMessage = "File is not a XCOFF32 or XCOFF64 binary."; + } +} + +cmXCOFF::~cmXCOFF() = default; + +cmXCOFF::cmXCOFF(cmXCOFF&&) = default; +cmXCOFF& cmXCOFF::operator=(cmXCOFF&&) = default; + +bool cmXCOFF::Valid() const +{ + return this->Internal && this->ErrorMessage.empty(); +} + +cm::optional cmXCOFF::GetLibPath() const +{ + cm::optional result; + if (this->Valid()) { + result = this->Internal->GetLibPath(); + } + return result; +} + +bool cmXCOFF::SetLibPath(cm::string_view libPath) +{ + return this->Valid() && this->Internal->GetMode() == Mode::ReadWrite && + this->Internal->SetLibPath(libPath); +} + +bool cmXCOFF::RemoveLibPath() +{ + return this->Valid() && this->Internal->GetMode() == Mode::ReadWrite && + this->Internal->RemoveLibPath(); +} diff --git a/Source/cmXCOFF.h b/Source/cmXCOFF.h new file mode 100644 index 0000000..16cda9d --- /dev/null +++ b/Source/cmXCOFF.h @@ -0,0 +1,65 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include +#include +#include + +#include +#include + +#if !defined(CMake_USE_XCOFF_PARSER) +# error "This file may be included only if CMake_USE_XCOFF_PARSER is enabled." +#endif + +class cmXCOFFInternal; + +/** \class cmXCOFF + * \brief XCOFF parser. + */ +class cmXCOFF +{ +public: + enum class Mode + { + ReadOnly, + ReadWrite + }; + + /** Construct with the name of the XCOFF input file to parse. */ + cmXCOFF(const char* fname, Mode = Mode::ReadOnly); + + /** Destruct. */ + ~cmXCOFF(); + + cmXCOFF(cmXCOFF&&); + cmXCOFF(cmXCOFF const&) = delete; + cmXCOFF& operator=(cmXCOFF&&); + cmXCOFF& operator=(cmXCOFF const&) = delete; + + /** Get the error message if any. */ + std::string const& GetErrorMessage() const { return this->ErrorMessage; } + + /** Boolean conversion. True if the XCOFF file is valid. */ + explicit operator bool() const { return this->Valid(); } + + /** Get the LIBPATH (RPATH) parsed from the file, if any. */ + cm::optional GetLibPath() const; + + /** Set the LIBPATH (RPATH). + Works only if cmXCOFF was constructed with Mode::ReadWrite. */ + bool SetLibPath(cm::string_view libPath); + + /** Remove the LIBPATH (RPATH). + Works only if cmXCOFF was constructed with Mode::ReadWrite. */ + bool RemoveLibPath(); + +private: + friend class cmXCOFFInternal; + bool Valid() const; + std::unique_ptr Internal; + std::string ErrorMessage; +}; -- cgit v0.12 From e017ba046ccab62fcc67e7cf8fc858e991c1d3e7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 2 Feb 2021 19:27:09 -0500 Subject: AIX: Enable XCOFF editing to replace RPATH on installation Avoid relinking before installation. --- Help/release/dev/aix-xcoff-edit.rst | 8 ++ Source/cmGeneratorTarget.cxx | 27 +++-- Source/cmSystemTools.cxx | 113 ++++++++++++++++++++- Tests/RunCMake/CMakeLists.txt | 4 +- Tests/RunCMake/file-RPATH/RunCMakeTest.cmake | 4 + Tests/RunCMake/file-RPATH/XCOFF.cmake | 7 ++ Tests/RunCMake/install/RunCMakeTest.cmake | 10 +- .../TARGETS-FILE_RPATH_CHANGE-check-common.cmake | 2 + 8 files changed, 157 insertions(+), 18 deletions(-) create mode 100644 Help/release/dev/aix-xcoff-edit.rst create mode 100644 Tests/RunCMake/file-RPATH/XCOFF.cmake diff --git a/Help/release/dev/aix-xcoff-edit.rst b/Help/release/dev/aix-xcoff-edit.rst new file mode 100644 index 0000000..be3143d --- /dev/null +++ b/Help/release/dev/aix-xcoff-edit.rst @@ -0,0 +1,8 @@ +aix-xcoff-edit +-------------- + +* On AIX, installation of XCOFF executables and shared libraries + no longer requires relinking to change the runtime search path + from the build-tree RPATH to the install-tree RPATH. CMake now + edits the XCOFF binaries directly during installation, as has + long been done on ELF platforms. diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 0171d8a..9235faa 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -2009,10 +2009,10 @@ bool cmGeneratorTarget::NeedRelinkBeforeInstall( std::ostringstream w; /* clang-format off */ w << - "The install of the " << this->GetName() << " target requires " - "changing an RPATH from the build tree, but this is not supported " - "with the Ninja generator unless on an ELF-based platform. The " - "CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this " + "The install of the " << this->GetName() << " target requires changing " + "an RPATH from the build tree, but this is not supported with the Ninja " + "generator unless on an ELF-based or XCOFF-based platform. " + "The CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this " "relinking step." ; /* clang-format on */ @@ -2058,20 +2058,29 @@ bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const return true; } -#if defined(CMake_USE_ELF_PARSER) - // Enable if the rpath flag uses a separator and the target uses ELF - // binaries. +#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER) + // Enable if the rpath flag uses a separator and the target uses + // binaries we know how to edit. std::string ll = this->GetLinkerLanguage(config); if (!ll.empty()) { std::string sepVar = cmStrCat("CMAKE_SHARED_LIBRARY_RUNTIME_", ll, "_FLAG_SEP"); cmProp sep = this->Makefile->GetDefinition(sepVar); if (cmNonempty(sep)) { - // TODO: Add ELF check to ABI detection and get rid of + // TODO: Add binary format check to ABI detection and get rid of // CMAKE_EXECUTABLE_FORMAT. if (cmProp fmt = this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT")) { - return (*fmt == "ELF"); +# if defined(CMake_USE_ELF_PARSER) + if (*fmt == "ELF") { + return true; + } +# endif +# if defined(CMake_USE_XCOFF_PARSER) + if (*fmt == "XCOFF") { + return true; + } +# endif } } } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 8c5a657..0807590 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -53,6 +53,10 @@ # include "cmMachO.h" #endif +#if defined(CMake_USE_XCOFF_PARSER) +# include "cmXCOFF.h" +#endif + #include #include #include @@ -2360,9 +2364,9 @@ bool cmSystemTools::GuessLibraryInstallName(std::string const& fullPath, return false; } -#if defined(CMake_USE_ELF_PARSER) -std::string::size_type cmSystemToolsFindRPath(std::string const& have, - std::string const& want) +#if defined(CMake_USE_ELF_PARSER) || defined(CMake_USE_XCOFF_PARSER) +std::string::size_type cmSystemToolsFindRPath(cm::string_view const& have, + cm::string_view const& want) { std::string::size_type pos = 0; while (pos < have.size()) { @@ -2404,6 +2408,7 @@ struct cmSystemToolsRPathInfo }; #endif +// FIXME: Dispatch if multiple formats are supported. #if defined(CMake_USE_ELF_PARSER) bool cmSystemTools::ChangeRPath(std::string const& file, std::string const& oldRPath, @@ -2576,6 +2581,75 @@ bool cmSystemTools::ChangeRPath(std::string const& file, } return true; } +#elif defined(CMake_USE_XCOFF_PARSER) +bool cmSystemTools::ChangeRPath(std::string const& file, + std::string const& oldRPath, + std::string const& newRPath, + bool removeEnvironmentRPath, std::string* emsg, + bool* changed) +{ + if (changed) { + *changed = false; + } + + bool chg = false; + cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite); + if (cm::optional maybeLibPath = xcoff.GetLibPath()) { + cm::string_view libPath = *maybeLibPath; + // Make sure the current rpath contains the old rpath. + std::string::size_type pos = cmSystemToolsFindRPath(libPath, oldRPath); + if (pos == std::string::npos) { + // If it contains the new rpath instead then it is okay. + if (cmSystemToolsFindRPath(libPath, newRPath) != std::string::npos) { + return true; + } + if (emsg) { + std::ostringstream e; + /* clang-format off */ + e << "The current RPATH is:\n" + << " " << libPath << "\n" + << "which does not contain:\n" + << " " << oldRPath << "\n" + << "as was expected."; + /* clang-format on */ + *emsg = e.str(); + } + return false; + } + + // The prefix is either empty or ends in a ':'. + cm::string_view prefix = libPath.substr(0, pos); + if (newRPath.empty() && !prefix.empty()) { + prefix.remove_suffix(1); + } + + // The suffix is either empty or starts in a ':'. + cm::string_view suffix = libPath.substr(pos + oldRPath.length()); + + // Construct the new value which preserves the part of the path + // not being changed. + std::string newLibPath; + if (!removeEnvironmentRPath) { + newLibPath = std::string(prefix); + } + newLibPath += newRPath; + newLibPath += suffix; + + chg = xcoff.SetLibPath(newLibPath); + } + if (!xcoff) { + if (emsg) { + *emsg = xcoff.GetErrorMessage(); + } + return false; + } + + // Everything was updated successfully. + if (changed) { + *changed = chg; + } + return true; +} #else bool cmSystemTools::ChangeRPath(std::string const& /*file*/, std::string const& /*oldRPath*/, @@ -2720,6 +2794,7 @@ int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs) return cm_strverscmp(lhs.c_str(), rhs.c_str()); } +// FIXME: Dispatch if multiple formats are supported. #if defined(CMake_USE_ELF_PARSER) bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, bool* removed) @@ -2861,6 +2936,28 @@ bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, } return true; } +#elif defined(CMake_USE_XCOFF_PARSER) +bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, + bool* removed) +{ + if (removed) { + *removed = false; + } + + cmXCOFF xcoff(file.c_str(), cmXCOFF::Mode::ReadWrite); + bool rm = xcoff.RemoveLibPath(); + if (!xcoff) { + if (emsg) { + *emsg = xcoff.GetErrorMessage(); + } + return false; + } + + if (removed) { + *removed = rm; + } + return true; +} #else bool cmSystemTools::RemoveRPath(std::string const& /*file*/, std::string* /*emsg*/, bool* /*removed*/) @@ -2869,6 +2966,7 @@ bool cmSystemTools::RemoveRPath(std::string const& /*file*/, } #endif +// FIXME: Dispatch if multiple formats are supported. bool cmSystemTools::CheckRPath(std::string const& file, std::string const& newRPath) { @@ -2894,6 +2992,15 @@ bool cmSystemTools::CheckRPath(std::string const& file, } } return false; +#elif defined(CMake_USE_XCOFF_PARSER) + // Parse the XCOFF binary. + cmXCOFF xcoff(file.c_str()); + if (cm::optional libPath = xcoff.GetLibPath()) { + if (cmSystemToolsFindRPath(*libPath, newRPath) != std::string::npos) { + return true; + } + } + return false; #else (void)file; (void)newRPath; diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index e0804d7..549d8eb 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -358,8 +358,8 @@ add_RunCMake_test(ctest_upload) add_RunCMake_test(ctest_fixtures) add_RunCMake_test(file) add_RunCMake_test(file-CHMOD) -if(HAVE_ELF_H) - add_RunCMake_test(file-RPATH -DHAVE_ELF_H=${HAVE_ELF_H}) +if(HAVE_ELF_H OR CMAKE_SYSTEM_NAME STREQUAL "AIX") + add_RunCMake_test(file-RPATH -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DHAVE_ELF_H=${HAVE_ELF_H}) endif() add_RunCMake_test(find_file) add_RunCMake_test(find_library -DCYGWIN=${CYGWIN}) diff --git a/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake b/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake index 11e90bb..eb7b497 100644 --- a/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake +++ b/Tests/RunCMake/file-RPATH/RunCMakeTest.cmake @@ -3,3 +3,7 @@ include(RunCMake) if(HAVE_ELF_H) run_cmake_command(ELF ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/ELF.cmake) endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "AIX") + run_cmake_command(XCOFF ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/XCOFF.cmake) +endif() diff --git a/Tests/RunCMake/file-RPATH/XCOFF.cmake b/Tests/RunCMake/file-RPATH/XCOFF.cmake new file mode 100644 index 0000000..b570920 --- /dev/null +++ b/Tests/RunCMake/file-RPATH/XCOFF.cmake @@ -0,0 +1,7 @@ +set(names + xcoff32.bin + xcoff64.bin + ) +set(format XCOFF) + +include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake) diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index b067b3a..efd03df 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/Tests/RunCMake/install/RunCMakeTest.cmake @@ -48,14 +48,16 @@ in directory: endif() endfunction() -# Wrapper for run_cmake() that skips platforms that are non-ELF or have no RPATH support -function(run_cmake_ELFRPATH_only case) - if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF") +# Wrapper for run_cmake() that skips platforms on which we do not support editing the RPATH. +function(run_cmake_EDIT_RPATH_only case) + if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT MATCHES "^(ELF|XCOFF)$") run_cmake(${case}) else() # Sanity check against a platform known to be ELF-based if(CMAKE_SYSTEM_NAME STREQUAL "Linux") message(FATAL_ERROR "Expected platform Linux to advertize itself as ELF-based, but it did not.") + elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX") + message(FATAL_ERROR "Expected platform AIX to advertize itself as XCOFF-based, but it did not.") else() message(STATUS "${case} - SKIPPED (No ELF-based platform found)") endif() @@ -63,7 +65,7 @@ function(run_cmake_ELFRPATH_only case) endfunction() run_cmake(TARGETS-FILE_RPATH_CHANGE-old_rpath) -run_cmake_ELFRPATH_only(TARGETS-FILE_RPATH_CHANGE-new_rpath) +run_cmake_EDIT_RPATH_only(TARGETS-FILE_RPATH_CHANGE-new_rpath) run_cmake(DIRECTORY-MESSAGE_NEVER) run_cmake(DIRECTORY-PATTERN-MESSAGE_NEVER) run_cmake(DIRECTORY-message) diff --git a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake index 673fdde..6b2faa3 100644 --- a/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake +++ b/Tests/RunCMake/install/TARGETS-FILE_RPATH_CHANGE-check-common.cmake @@ -22,6 +22,8 @@ macro(skip_without_rpath_change_rule) # Sanity check against a platform known to generate a file(RPATH_CHANGE) rule if(CMAKE_SYSTEM_NAME STREQUAL "Linux") message(FATAL_ERROR "Expected generated file(RPATH_CHANGE) rule on platform Linux.") + elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX") + message(FATAL_ERROR "Expected generated file(RPATH_CHANGE) rule on platform AIX.") else() message(STATUS "${test} - All checks skipped. No file(RPATH_CHANGE) rule found on this platform.") return() -- cgit v0.12