Build failure on Linux with CMake 3.22 (libc++.so RPATH_CHANGE)

My local Linux build of LLVM trunk (where LLVM_ENABLE_PROJECTS contains libcxx;libcxxabi, among others) started to fail when I upgraded my Fedora 35 machine from cmake-3.21.3-1.fc35.x86_64 to cmake-3.22.0-1.fc35.x86_64, but I know too little about CMake and its use in the LLVM build system to tell whether this is a bug in CMake or in how LLVM uses it:

`cmake --build . --target install` started to fail with

-- Installing: /home/sbergman/llvm/inst/lib/libc++.so
CMake Error at projects/libcxx/src/cmake_install.cmake:88 (file):
  file RPATH_CHANGE could not write new RPATH:

  to the file:

    /home/sbergman/llvm/inst/lib/libc++.so

Call Stack (most recent call first):
  projects/libcxx/cmake_install.cmake:56 (include)
  projects/cmake_install.cmake:48 (include)
  cmake_install.cmake:76 (include)

FAILED: CMakeFiles/install.util cd /home/sbergman/llvm/build && /usr/bin/cmake -P cmake_install.cmake
ninja: build stopped: subcommand failed.

where ~/llvm/inst/lib/libc++.so is a plain text file containing the single line

INPUT(libc++.so.1 -lc++abi)

and the relevant section of ~/llvm/build/projects/libcxx/src/cmake_install.cmake:78 is

if("x${CMAKE_INSTALL_COMPONENT}x" STREQUAL "xcxxx" OR NOT CMAKE_INSTALL_COMPONENT)
  if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libc++.so" AND
     NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libc++.so")
    file(RPATH_CHECK
         FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libc++.so"
         RPATH "")
  endif()
  file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE SHARED_LIBRARY FILES "/home/sbergman/llvm/build/lib/libc++.so")
  if(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libc++.so" AND
     NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libc++.so")
    file(RPATH_CHANGE
         FILE "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libc++.so"
         OLD_RPATH "/home/sbergman/llvm/build/lib:"
         NEW_RPATH "")
    if(CMAKE_INSTALL_DO_STRIP)
      execute_process(COMMAND "/usr/bin/llvm-strip" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libc++.so")
    endif()
  endif()
endif()

Bisecting CMake pointed at <https://gitlab.kitware.com/cmake/cmake/-/commit/2e1149874d34b63cc16c7330ce1ef5ef779e5140> "cmSystemTools: Support multiple binary formats" as the problematic change: Before that change, cmSystemTools::ChangeRPath -> AdjustRPath on a non-ELF file called

    if (se_count == 0) {
      return emptyCallback(emsg, elf);
    }

calling MakeEmptyCallback's

    if (newRPath.empty()) {
      // The new rpath is empty and there is no rpath anyway so it is
      // okay.
      return true;
    }

and thus returning true. But after the change ChangeRPathELF returns an empty std::optional, so that cmSystemTools::ChangeRPath returns false, causing the failure.

What would help my build along is the CMake change

diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 3699be3a5a..7099581ab4 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -2855,7 +2855,7 @@ bool cmSystemTools::ChangeRPath(std::string const& file,
         file, oldRPath, newRPath, removeEnvironmentRPath, emsg, changed)) {
     return result.value();
   }
- return false;
+ return newRPath.empty();
}
  bool cmSystemTools::SetRPath(std::string const& file,
~

However, I don't know whether RPATH_CHANGE legitimately gets called on that non-ELF libc++.so text file in the first place.

CMake maintains backwards compatibility. Any breakage that's not behind a policy is considered a bug.

Someone else seems to already have opened an issue: https://gitlab.kitware.com/cmake/cmake/-/issues/22963