Merge topic 'doc-INSTALL_PREFIX'

925f9f18dd Help: INSTALL_PREFIX in install(CODE|SCRIPT) was added in CMake 3.27

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Alex <leha-bot@yandex.ru>
Acked-by: Frank Dana <ferdnyc@gmail.com>
Merge-request: !9135
diff --git a/Help/guide/tutorial/Adding Generator Expressions.rst b/Help/guide/tutorial/Adding Generator Expressions.rst
index 910eacb..d2dddf7 100644
--- a/Help/guide/tutorial/Adding Generator Expressions.rst
+++ b/Help/guide/tutorial/Adding Generator Expressions.rst
@@ -24,7 +24,7 @@
 
 Logical expressions are used to create conditional output. The basic
 expressions are the ``0`` and ``1`` expressions. A ``$<0:...>`` results in the
-empty string, and ``<1:...>`` results in the content of ``...``.  They can also
+empty string, and ``$<1:...>`` results in the content of ``...``.  They can also
 be nested.
 
 Exercise 1 - Adding Compiler Warning Flags with Generator Expressions
diff --git a/Help/guide/tutorial/Adding a Library.rst b/Help/guide/tutorial/Adding a Library.rst
index 18ced97..cfcfc67 100644
--- a/Help/guide/tutorial/Adding a Library.rst
+++ b/Help/guide/tutorial/Adding a Library.rst
@@ -145,10 +145,10 @@
 
   </details>
 
-Finally we need to specify the library's header file location. Modify
-:command:`target_include_directories` to add the ``MathFunctions`` subdirectory
-as an include directory so that the ``MathFunctions.h`` header file can be
-found.
+Finally we need to specify the library's header file location.
+Modify the existing :command:`target_include_directories` call
+to add the ``MathFunctions`` subdirectory as an include directory
+so that the ``MathFunctions.h`` header file can be found.
 
 .. raw:: html
 
diff --git a/Help/guide/tutorial/Step12/CMakeLists.txt b/Help/guide/tutorial/Step12/CMakeLists.txt
index 1d8b5a6..1ba4e31 100644
--- a/Help/guide/tutorial/Step12/CMakeLists.txt
+++ b/Help/guide/tutorial/Step12/CMakeLists.txt
@@ -97,7 +97,7 @@
 # generate the config file that includes the exports
 configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
   "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
-  INSTALL_DESTINATION "lib/cmake/example"
+  INSTALL_DESTINATION "lib/cmake/MathFunctions"
   NO_SET_AND_CHECK_MACRO
   NO_CHECK_REQUIRED_COMPONENTS_MACRO
   )
diff --git a/Help/policy/CMP0158.rst b/Help/policy/CMP0158.rst
index 4289c6d..369b5ec 100644
--- a/Help/policy/CMP0158.rst
+++ b/Help/policy/CMP0158.rst
@@ -25,3 +25,5 @@
 :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 Unlike many policies, CMake version |release| does *not* warn
 when this policy is not set and simply uses ``OLD`` behavior.
+
+.. include:: DEPRECATED.txt
diff --git a/Modules/Compiler/LCC-C.cmake b/Modules/Compiler/LCC-C.cmake
index 3dd6e68..99f791f 100644
--- a/Modules/Compiler/LCC-C.cmake
+++ b/Modules/Compiler/LCC-C.cmake
@@ -12,18 +12,25 @@
 
 set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
 
-set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
-set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
-set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 1.23)
+  set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")
+  set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu90")
+  set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
 set(CMAKE_C99_STANDARD_COMPILE_OPTION "-std=c99")
 set(CMAKE_C99_EXTENSION_COMPILE_OPTION "-std=gnu99")
 set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
-set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
-set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
-set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
-set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
-set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
-set(CMAKE_C23_STANDARD_COMPILE_OPTION "-std=c2x")
-set(CMAKE_C23_EXTENSION_COMPILE_OPTION "-std=gnu2x")
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 1.20)
+  set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
+  set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")
+  set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 1.26)
+  set(CMAKE_C17_STANDARD_COMPILE_OPTION "-std=c17")
+  set(CMAKE_C17_EXTENSION_COMPILE_OPTION "-std=gnu17")
+endif()
 
 __compiler_check_default_language_standard(C 1.23 90 1.20 11 1.26 17)
diff --git a/Modules/Compiler/LCC-CXX.cmake b/Modules/Compiler/LCC-CXX.cmake
index b3bdd3c..385947a 100644
--- a/Modules/Compiler/LCC-CXX.cmake
+++ b/Modules/Compiler/LCC-CXX.cmake
@@ -17,15 +17,27 @@
 set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
 set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
 set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
-set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
-set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
-set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
-set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
-set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
-set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
-set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17")
-set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
-set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++2a")
-set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a")
+
+if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 1.20)
+  set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
+  set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+  set(CMAKE_CXX11_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 1.21)
+  set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14")
+  set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14")
+  set(CMAKE_CXX14_STANDARD__HAS_FULL_SUPPORT ON)
+endif()
+
+if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 1.24)
+  set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++17")
+  set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17")
+endif()
+
+if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 1.26)
+  set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++2a")
+  set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a")
+endif()
 
 __compiler_check_default_language_standard(CXX 1.19 98 1.20 11 1.21 14 1.24 17 1.26 20)
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index 469a7ad..ac72c17 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -1100,7 +1100,10 @@
     if(CUDA_${lib_name}_LIBRARY MATCHES "/stubs/" AND NOT WIN32)
       # Use a SHARED library with IMPORTED_IMPLIB, but not IMPORTED_LOCATION,
       # to indicate that the stub is for linkers but not dynamic loaders.
-      # It will not contribute any RPATH entry.
+      # It will not contribute any RPATH entry.  When encountered as
+      # a private transitive dependency of another shared library,
+      # it will be passed explicitly to linkers so they can find it
+      # even when the runtime library file does not exist on disk.
       set(CUDA_IMPORT_PROPERTY IMPORTED_IMPLIB)
       set(CUDA_IMPORT_TYPE     SHARED)
     endif()
diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake
index 0ba35b6..d55c4ca 100644
--- a/Modules/GetPrerequisites.cmake
+++ b/Modules/GetPrerequisites.cmake
@@ -514,7 +514,7 @@
     string(TOLOWER "${resolved_file}" lower)
 
     if(UNIX)
-      if(resolved_file MATCHES "^(/lib/|/lib32/|/libx32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/libx32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
+      if(resolved_file MATCHES "^/*(/lib/|/lib32/|/libx32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/libx32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
         set(is_system 1)
       endif()
     endif()
diff --git a/Modules/Internal/CPack/CPack.NuGet.nuspec.in b/Modules/Internal/CPack/CPack.NuGet.nuspec.in
index d89d69f..4548a59 100644
--- a/Modules/Internal/CPack/CPack.NuGet.nuspec.in
+++ b/Modules/Internal/CPack/CPack.NuGet.nuspec.in
@@ -15,12 +15,14 @@
         @_CPACK_NUGET_LICENSE_TAG@
         @_CPACK_NUGET_ICONURL_TAG@
         @_CPACK_NUGET_ICON_TAG@
+        @_CPACK_NUGET_README_TAG@
         @_CPACK_NUGET_REQUIRELICENSEACCEPTANCE_TAG@
         @_CPACK_NUGET_SUMMARY_TAG@
         @_CPACK_NUGET_RELEASENOTES_TAG@
         @_CPACK_NUGET_COPYRIGHT_TAG@
         @_CPACK_NUGET_LANGUAGE_TAG@
         @_CPACK_NUGET_TAGS_TAG@
+        @_CPACK_NUGET_REPOSITORY_TAG@
         @_CPACK_NUGET_DEPENDENCIES_TAG@
     </metadata>
     @_CPACK_NUGET_FILES_TAG@
diff --git a/Modules/Internal/CPack/CPackNuGet.cmake b/Modules/Internal/CPack/CPackNuGet.cmake
index 056d025..67f318a 100644
--- a/Modules/Internal/CPack/CPackNuGet.cmake
+++ b/Modules/Internal/CPack/CPackNuGet.cmake
@@ -294,6 +294,27 @@
     # attributes: "type", "url", "branch", and "commit". While all fields are
     # considered optional, they are not independent. Currently unsupported.
 
+    # NuGet >= 5.10
+    _cpack_nuget_variable_fallback_and_wrap_into_element(readme README)
+
+    set(_CPACK_NUGET_REPOSITORY_TAG)
+    _cpack_nuget_variable_fallback(_repo_type REPOSITORY_TYPE)
+    _cpack_nuget_variable_fallback(_repo_url REPOSITORY_URL)
+    if(_repo_type AND _repo_url)
+        set(_CPACK_NUGET_REPOSITORY_TAG "<repository type=\"${_repo_type}\" url=\"${_repo_url}\"")
+        _cpack_nuget_variable_fallback(_repo_br REPOSITORY_BRANCH)
+        if(_repo_br)
+            string(APPEND _CPACK_NUGET_REPOSITORY_TAG " branch=\"${_repo_br}\"")
+        endif()
+        _cpack_nuget_variable_fallback(_repo_commit REPOSITORY_COMMIT)
+        if(_repo_commit)
+            string(APPEND _CPACK_NUGET_REPOSITORY_TAG " commit=\"${_repo_commit}\"")
+        endif()
+        string(APPEND _CPACK_NUGET_REPOSITORY_TAG " />")
+    else()
+        message(AUTHOR_WARNING "Skip adding the `<repository .../>` element due to missing URL or type")
+    endif()
+
     # Handle dependencies
     _cpack_nuget_variable_fallback(_deps DEPENDENCIES)
     set(_collected_deps)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index fc137cf..fb119ae 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 28)
-set(CMake_VERSION_PATCH 20240106)
+set(CMake_VERSION_PATCH 20240109)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx
index ab77818..2a6a831 100644
--- a/Source/QtDialog/CMakeSetupDialog.cxx
+++ b/Source/QtDialog/CMakeSetupDialog.cxx
@@ -875,7 +875,7 @@
     if (preset.setToolset) {
       dialog.setToolset(preset.toolset);
     }
-    dialog.setCompilerOption(CompilerOption::DefaultNative);
+    dialog.setCompilerOption(CompilerOption::DefaultPreset);
   }
 
   if (dialog.exec() == QDialog::Accepted) {
diff --git a/Source/QtDialog/FirstConfigure.cxx b/Source/QtDialog/FirstConfigure.cxx
index a454cb6..2986e1f 100644
--- a/Source/QtDialog/FirstConfigure.cxx
+++ b/Source/QtDialog/FirstConfigure.cxx
@@ -159,6 +159,10 @@
 {
   std::size_t index = 0;
   switch (option) {
+    case CompilerOption::DefaultPreset:
+      this->CompilerSetupOptions[0]->setText(
+        tr("Use default preset compilers"));
+      CM_FALLTHROUGH;
     case CompilerOption::DefaultNative:
       index = 0;
       break;
diff --git a/Source/QtDialog/FirstConfigure.h b/Source/QtDialog/FirstConfigure.h
index 5844f3a..ea6fae6 100644
--- a/Source/QtDialog/FirstConfigure.h
+++ b/Source/QtDialog/FirstConfigure.h
@@ -24,6 +24,7 @@
 
 enum class CompilerOption
 {
+  DefaultPreset,
   DefaultNative,
   SpecifyNative,
   ToolchainFile,
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index f43f05f..8d63f6d 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -378,6 +378,54 @@
   this->CMakeInstance->SaveCache(this->BinaryDirectory.toStdString());
 }
 
+namespace {
+template <typename T>
+QCMakeProperty cache_to_property(const T& v)
+{
+  QCMakeProperty prop;
+  prop.Key = QString::fromStdString(v.first);
+  prop.Value = QString::fromStdString(v.second->Value);
+  prop.Type = QCMakeProperty::STRING;
+  if (!v.second->Type.empty()) {
+    auto type = cmState::StringToCacheEntryType(v.second->Type);
+    switch (type) {
+      case cmStateEnums::BOOL:
+        prop.Type = QCMakeProperty::BOOL;
+        prop.Value = cmIsOn(v.second->Value);
+        break;
+      case cmStateEnums::PATH:
+        prop.Type = QCMakeProperty::PATH;
+        break;
+      case cmStateEnums::FILEPATH:
+        prop.Type = QCMakeProperty::FILEPATH;
+        break;
+      default:
+        prop.Type = QCMakeProperty::STRING;
+        break;
+    }
+  }
+  return prop;
+}
+
+void add_to_property_list(QCMakePropertyList& list, QCMakeProperty&& prop)
+{
+  // QCMakeCacheModel prefers variables earlier in the list rather than
+  // later, so overwrite them if they already exist rather than simply
+  // appending
+  bool found = false;
+  for (auto& orig : list) {
+    if (orig.Key == prop.Key) {
+      orig = prop;
+      found = true;
+      break;
+    }
+  }
+  if (!found) {
+    list.append(prop);
+  }
+}
+}
+
 QCMakePropertyList QCMake::properties() const
 {
   QCMakePropertyList ret;
@@ -423,47 +471,21 @@
     auto const& p =
       this->CMakePresetsGraph.ConfigurePresets.at(presetName).Expanded;
     if (p) {
+      if (!p->ToolchainFile.empty()) {
+        using CacheVariable = cmCMakePresetsGraph::CacheVariable;
+        CacheVariable var{ "FILEPATH", p->ToolchainFile };
+        std::pair<std::string, cm::optional<CacheVariable>> value = {
+          "CMAKE_TOOLCHAIN_FILE", var
+        };
+        auto prop = cache_to_property(value);
+        add_to_property_list(ret, std::move(prop));
+      }
       for (auto const& v : p->CacheVariables) {
         if (!v.second) {
           continue;
         }
-        QCMakeProperty prop;
-        prop.Key = QString::fromStdString(v.first);
-        prop.Value = QString::fromStdString(v.second->Value);
-        prop.Type = QCMakeProperty::STRING;
-        if (!v.second->Type.empty()) {
-          auto type = cmState::StringToCacheEntryType(v.second->Type);
-          switch (type) {
-            case cmStateEnums::BOOL:
-              prop.Type = QCMakeProperty::BOOL;
-              prop.Value = cmIsOn(v.second->Value);
-              break;
-            case cmStateEnums::PATH:
-              prop.Type = QCMakeProperty::PATH;
-              break;
-            case cmStateEnums::FILEPATH:
-              prop.Type = QCMakeProperty::FILEPATH;
-              break;
-            default:
-              prop.Type = QCMakeProperty::STRING;
-              break;
-          }
-        }
-
-        // QCMakeCacheModel prefers variables earlier in the list rather than
-        // later, so overwrite them if they already exist rather than simply
-        // appending
-        bool found = false;
-        for (auto& orig : ret) {
-          if (orig.Key == prop.Key) {
-            orig = prop;
-            found = true;
-            break;
-          }
-        }
-        if (!found) {
-          ret.append(prop);
-        }
+        auto prop = cache_to_property(v);
+        add_to_property_list(ret, std::move(prop));
       }
     }
   }
diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h
index 89068ab..549cca2 100644
--- a/Source/QtDialog/QCMakeCacheView.h
+++ b/Source/QtDialog/QCMakeCacheView.h
@@ -91,10 +91,6 @@
                       const QString& description, const QVariant& value,
                       bool advanced);
 
-  // set the view type
-  void setViewType(ViewType t);
-  ViewType viewType() const;
-
 public:
   // get the properties
   QCMakePropertyList properties() const;
@@ -112,6 +108,10 @@
   // get the data in the model for this property
   void getPropertyData(const QModelIndex& idx1, QCMakeProperty& prop) const;
 
+  // set the view type
+  void setViewType(ViewType t);
+  ViewType viewType() const;
+
 protected:
   bool EditEnabled;
   int NewPropertyCount;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 1b69f6e..40eb902 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -260,7 +260,7 @@
   , Config(config)
 {
   // Check whether to recognize OpenBSD-style library versioned names.
-  this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
+  this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
     "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
 
   // Allocate internals.
@@ -1331,7 +1331,17 @@
   }
 
   // If in linking mode, just link to the shared library.
-  if (this->SharedDependencyMode == SharedDepModeLink) {
+  if (this->SharedDependencyMode == SharedDepModeLink ||
+      // For an imported shared library without a known runtime artifact,
+      // such as a CUDA stub, a library file named with the real soname
+      // may not be available at all, so '-rpath-link' cannot help linkers
+      // find it to satisfy '--no-allow-shlib-undefined' recursively.
+      // Pass this dependency to the linker explicitly just in case.
+      // If the linker also uses '--as-needed' behavior, this will not
+      // add an unnecessary direct dependency.
+      (tgt && tgt->IsImported() &&
+       !tgt->HasKnownRuntimeArtifactLocation(this->Config) &&
+       this->Target->LinkerEnforcesNoAllowShLibUndefined(this->Config))) {
     this->AddItem(entry);
     return;
   }
@@ -1574,7 +1584,7 @@
   libext += ')';
 
   // Add an optional OpenBSD-style version or major.minor.version component.
-  if (this->OpenBSD || type == LinkShared) {
+  if (this->IsOpenBSD || type == LinkShared) {
     libext += "(\\.[0-9]+)*";
   }
 
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index 3ee995f..2a06530 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -254,7 +254,7 @@
   std::unique_ptr<cmOrderDirectories> OrderRuntimeSearchPath;
 
   bool OldLinkDirMode;
-  bool OpenBSD;
+  bool IsOpenBSD;
   bool LinkDependsNoShared;
   bool RuntimeUseChrpath;
   bool NoSONameUsesPath;
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index e764545..483a601 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -35,7 +35,11 @@
 namespace {
 bool cmExecuteProcessCommandIsWhitespace(char c)
 {
-  return (isspace(static_cast<int>(c)) || c == '\n' || c == '\r');
+  // isspace takes 'int' but documents that the value must be representable
+  // by 'unsigned char', or EOF.  Cast to 'unsigned char' to avoid sign
+  // extension while casting to 'int'.
+  return (isspace(static_cast<int>(static_cast<unsigned char>(c))) ||
+          c == '\n' || c == '\r');
 }
 
 void cmExecuteProcessCommandFixText(std::vector<char>& output,
diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx
index df77ad0..9df7665 100644
--- a/Source/cmFindLibraryCommand.cxx
+++ b/Source/cmFindLibraryCommand.cxx
@@ -207,7 +207,7 @@
   std::string BestPath;
 
   // Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor>
-  bool OpenBSD;
+  bool IsOpenBSD;
 
   bool DebugMode;
 
@@ -320,7 +320,7 @@
   this->RegexFromList(this->SuffixRegexStr, this->Suffixes);
 
   // Check whether to use OpenBSD-style library version comparisons.
-  this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
+  this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
     "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
 }
 
@@ -390,7 +390,7 @@
   std::string regex = cmStrCat('^', this->PrefixRegexStr);
   this->RegexFromLiteral(regex, name);
   regex += this->SuffixRegexStr;
-  if (this->OpenBSD) {
+  if (this->IsOpenBSD) {
     regex += "(\\.[0-9]+\\.[0-9]+)?";
   }
   regex += "$";
@@ -472,7 +472,7 @@
         size_type suffix = this->GetSuffixIndex(name.Regex.match(2));
         unsigned int major = 0;
         unsigned int minor = 0;
-        if (this->OpenBSD) {
+        if (this->IsOpenBSD) {
           sscanf(name.Regex.match(3).c_str(), ".%u.%u", &major, &minor);
         }
         if (this->BestPath.empty() || prefix < bestPrefix ||
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 289bb24..11253db 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5596,6 +5596,20 @@
   return linkerTool;
 }
 
+bool cmGeneratorTarget::LinkerEnforcesNoAllowShLibUndefined(
+  std::string const& config) const
+{
+  // FIXME(#25486): Account for the LINKER_TYPE target property.
+  // Also factor out the hard-coded list below into a platform
+  // information table based on the linker id.
+  std::string ll = this->GetLinkerLanguage(config);
+  std::string linkerIdVar = cmStrCat("CMAKE_", ll, "_COMPILER_LINKER_ID");
+  cmValue linkerId = this->Makefile->GetDefinition(linkerIdVar);
+  // The GNU bfd-based linker may enforce '--no-allow-shlib-undefined'
+  // recursively by default.  The Solaris linker has similar behavior.
+  return linkerId && (*linkerId == "GNU" || *linkerId == "Solaris");
+}
+
 std::string cmGeneratorTarget::GetPDBOutputName(
   const std::string& config) const
 {
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index cfb08fa..fb56a0d 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -805,6 +805,9 @@
   std::string GetLinkerTool(const std::string& lang,
                             const std::string& config) const;
 
+  /** Is the linker known to enforce '--no-allow-shlib-undefined'? */
+  bool LinkerEnforcesNoAllowShLibUndefined(std::string const& config) const;
+
   /** Does this target have a GNU implib to convert to MS format?  */
   bool HasImplibGNUtoMS(std::string const& config) const;
 
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index f038c6b..3f20dc0 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -484,7 +484,7 @@
   SELECT(POLICY, CMP0158,                                                     \
          "add_test() honors CMAKE_CROSSCOMPILING_EMULATOR only when "         \
          "cross-compiling.",                                                  \
-         3, 28, 0, cmPolicies::WARN)
+         3, 29, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 324a4da..cbd9cbc 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -345,7 +345,17 @@
   list(APPEND CompilerTest_ARGS -DCMake_TEST_OBJC=${CMake_TEST_OBJC})
 endif()
 if(CMAKE_Fortran_COMPILER)
-  list(APPEND CompilerTest_ARGS -DCMake_TEST_Fortran=1)
+  # lfortran < 1.24 cannot handle long file names.  Fortran is not
+  # enabled here, so check the C compiler version instead.
+  if(CMAKE_C_COMPILER_ID STREQUAL "LCC" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "1.24")
+    string(LENGTH "${CMAKE_CURRENT_BINARY_DIR}" _CCBD_LEN)
+    if(_CCBD_LEN LESS 35)
+      list(APPEND CompilerTest_ARGS -DCMake_TEST_Fortran=1)
+    endif()
+    unset(_CCBD_LEN)
+  else()
+    list(APPEND CompilerTest_ARGS -DCMake_TEST_Fortran=1)
+  endif()
 endif()
 foreach(lang IN ITEMS CUDA HIP ISPC)
   if(CMake_TEST_${lang})
@@ -434,8 +444,11 @@
 add_RunCMake_test(ObjectLibrary)
 add_RunCMake_test(ParseImplicitIncludeInfo)
 add_RunCMake_test(ParseImplicitLinkInfo)
-if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
-  add_RunCMake_test(RuntimePath)
+if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG)
+  add_RunCMake_test(RuntimePath
+    -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+    -DCMAKE_EXECUTABLE_FORMAT=${CMAKE_EXECUTABLE_FORMAT}
+    )
 endif()
 add_RunCMake_test(ScriptMode)
 add_RunCMake_test(Swift -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
@@ -1037,6 +1050,31 @@
 if(APPLE)
   list(APPEND cpack_tests DragNDrop)
 endif()
+
+if(CMAKE_SYSTEM_PROCESSOR STREQUAL "e2k" AND NOT DEFINED CMake_TEST_E2K_BROKEN_LIBC)
+  # Exclude tests that fail due to a broken libc version on Elbrus.
+  find_program(DPKG_QUERY "dpkg-query" )
+  execute_process(COMMAND "${DPKG_QUERY}" "-f" "\${Version}" "-W" "glibc" OUTPUT_VARIABLE LIBC_VERSION)
+  if(LIBC_VERSION MATCHES "2.29-25.*")
+    list(REMOVE_ITEM cpack_tests
+      DEB.AUTO_SUFFIXES
+      DEB.CUSTOM_NAMES
+      DEB.DEB_PACKAGE_VERSION_BACK_COMPATIBILITY
+      DEB.PROJECT_META DEB.DEPENDENCIES
+      RPM.PARTIALLY_RELOCATABLE_WARNING
+      RPM.PER_COMPONENT_FIELDS
+      RPM.USER_FILELIST
+      RPM.DIST
+      RPM.AUTO_SUFFIXES
+      TGZ
+      ZIP
+      STGZ
+      External
+      )
+    set(CMake_TEST_E2K_BROKEN_LIBC 1)
+  endif()
+endif()
+
 add_RunCMake_test_group(CPack "${cpack_tests}")
 # add a test to make sure symbols are exported from a shared library
 # for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
@@ -1091,14 +1129,16 @@
   -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
   -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
   )
-add_RunCMake_test(CMakePresetsTest
-  -DPython_EXECUTABLE=${Python_EXECUTABLE}
-  -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
-  )
-add_RunCMake_test(CMakePresetsPackage
-  -DPython_EXECUTABLE=${Python_EXECUTABLE}
-  -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
-  )
+if(NOT CMake_TEST_E2K_BROKEN_LIBC)
+  add_RunCMake_test(CMakePresetsTest
+    -DPython_EXECUTABLE=${Python_EXECUTABLE}
+    -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
+    )
+  add_RunCMake_test(CMakePresetsPackage
+    -DPython_EXECUTABLE=${Python_EXECUTABLE}
+    -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
+    )
+endif()
 add_RunCMake_test(CMakePresetsWorkflow
   -DPython_EXECUTABLE=${Python_EXECUTABLE}
   -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
diff --git a/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesFortran.cmake b/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesFortran.cmake
index 48dc525..68c5735 100644
--- a/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesFortran.cmake
+++ b/Tests/RunCMake/CheckSourceCompiles/CheckSourceCompilesFortran.cmake
@@ -5,6 +5,14 @@
 
 set(Fortran 1) # test that this is tolerated
 
+# lfortran < 1.24 cannot handle long file names.
+if(CMAKE_Fortran_COMPILER_ID STREQUAL "LCC" AND CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "1.24")
+  string(LENGTH "${CMAKE_CURRENT_BINARY_DIR}" _CCBD_LEN)
+  if(_CCBD_LEN GREATER_EQUAL 35)
+    return()
+  endif()
+endif()
+
 check_source_compiles(Fortran [=[
       PROGRAM TEST_HAVE_PRINT
         PRINT *, 'Hello'
diff --git a/Tests/RunCMake/CheckSourceRuns/CheckSourceRunsFortran.cmake b/Tests/RunCMake/CheckSourceRuns/CheckSourceRunsFortran.cmake
index 50e8ec8..fc5506a 100644
--- a/Tests/RunCMake/CheckSourceRuns/CheckSourceRunsFortran.cmake
+++ b/Tests/RunCMake/CheckSourceRuns/CheckSourceRunsFortran.cmake
@@ -5,6 +5,14 @@
 
 set(Fortran 1) # test that this is tolerated
 
+# lfortran < 1.24 cannot handle long file names.
+if(CMAKE_Fortran_COMPILER_ID STREQUAL "LCC" AND CMAKE_Fortran_COMPILER_VERSION VERSION_LESS "1.24")
+  string(LENGTH "${CMAKE_CURRENT_BINARY_DIR}" _CCBD_LEN)
+  if(_CCBD_LEN GREATER_EQUAL 35)
+    return()
+  endif()
+endif()
+
 check_source_runs(Fortran [=[
       PROGRAM TEST_HAVE_PRINT
         PRINT *, 'Hello'
diff --git a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
index ad446e9..180a0fe 100644
--- a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
+++ b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
@@ -21,12 +21,39 @@
   set(cfg_dir /Debug)
 endif()
 
-run_RuntimePath(SymlinkImplicit)
-run_cmake_command(SymlinkImplicitCheck
-  ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/SymlinkImplicit-build -Dcfg_dir=${cfg_dir} -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
+if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
+  run_RuntimePath(SymlinkImplicit)
+  run_cmake_command(SymlinkImplicitCheck
+    ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/SymlinkImplicit-build -Dcfg_dir=${cfg_dir} -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
 
-run_RuntimePath(Relative)
+  run_RuntimePath(Relative)
 
-run_RuntimePath(Genex)
-run_cmake_command(GenexCheck
-  ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/Genex-build -P ${RunCMake_SOURCE_DIR}/GenexCheck.cmake)
+  run_RuntimePath(Genex)
+  run_cmake_command(GenexCheck
+    ${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/Genex-build -P ${RunCMake_SOURCE_DIR}/GenexCheck.cmake)
+endif()
+
+block()
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Stub-build)
+  if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(bin_dir "${RunCMake_TEST_BINARY_DIR}/Debug")
+    set(lib_dir "${RunCMake_TEST_BINARY_DIR}/lib/Debug")
+  else()
+    set(bin_dir "${RunCMake_TEST_BINARY_DIR}")
+    set(lib_dir "${RunCMake_TEST_BINARY_DIR}/lib")
+  endif()
+  run_cmake(Stub)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(Stub-build ${CMAKE_COMMAND} --build . --config Debug)
+  if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|SunOS)$|BSD")
+    set(ldpath LD_LIBRARY_PATH)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "^(Darwin)$")
+    set(ldpath DYLD_LIBRARY_PATH)
+  elseif(CMAKE_SYSTEM_NAME MATCHES "^(AIX)$")
+    set(ldpath LIBPATH)
+  endif()
+  if(ldpath)
+    run_cmake_command(Stub-fail ${CMAKE_COMMAND} -E env LANG=C ${bin_dir}/StubExe)
+    run_cmake_command(Stub-pass ${CMAKE_COMMAND} -E env --modify ${ldpath}=path_list_prepend:${lib_dir} ${bin_dir}/StubExe)
+  endif()
+endblock()
diff --git a/Tests/RunCMake/RuntimePath/Stub-fail-result.txt b/Tests/RunCMake/RuntimePath/Stub-fail-result.txt
new file mode 100644
index 0000000..d197c91
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Stub-fail-result.txt
@@ -0,0 +1 @@
+[^0]
diff --git a/Tests/RunCMake/RuntimePath/Stub-fail-stderr.txt b/Tests/RunCMake/RuntimePath/Stub-fail-stderr.txt
new file mode 100644
index 0000000..9c17414
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Stub-fail-stderr.txt
@@ -0,0 +1 @@
+(error while loading shared libraries: libStub\.so\.1|Library not loaded: '?@rpath/libStub\.1\.dylib'?|(Cannot|Could not) load module libStub\.so|fatal: libStub\.so\.1: open failed|Shared object "libStub\.so\.1" not found)
diff --git a/Tests/RunCMake/RuntimePath/Stub.c b/Tests/RunCMake/RuntimePath/Stub.c
new file mode 100644
index 0000000..2ff333a
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Stub.c
@@ -0,0 +1,4 @@
+int Stub(void)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/RuntimePath/Stub.cmake b/Tests/RunCMake/RuntimePath/Stub.cmake
new file mode 100644
index 0000000..18e99c1
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Stub.cmake
@@ -0,0 +1,25 @@
+enable_language(C)
+
+add_library(Stub SHARED Stub.c)
+set_target_properties(Stub PROPERTIES
+  SOVERSION 1
+  LIBRARY_OUTPUT_DIRECTORY lib
+  )
+
+set(StubDir ${CMAKE_CURRENT_BINARY_DIR}/lib/stubs)
+set(Stub "${StubDir}/${CMAKE_SHARED_LIBRARY_PREFIX}Stub${CMAKE_SHARED_LIBRARY_SUFFIX}")
+add_custom_target(StubCopy
+  COMMAND ${CMAKE_COMMAND} -E make_directory "${StubDir}"
+  COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_SONAME_FILE:Stub>" "${Stub}"
+  BYPRODUCTS ${Stub}
+  )
+add_dependencies(StubCopy Stub)
+add_library(Imp::Stub SHARED IMPORTED)
+set_property(TARGET Imp::Stub PROPERTY IMPORTED_IMPLIB "${Stub}")
+add_dependencies(Imp::Stub StubCopy)
+
+add_library(StubUse SHARED StubUse.c)
+target_link_libraries(StubUse PRIVATE Imp::Stub)
+
+add_executable(StubExe StubExe.c)
+target_link_libraries(StubExe PRIVATE StubUse)
diff --git a/Tests/RunCMake/RuntimePath/StubExe.c b/Tests/RunCMake/RuntimePath/StubExe.c
new file mode 100644
index 0000000..14b3fe4
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/StubExe.c
@@ -0,0 +1,5 @@
+extern int StubUse(void);
+int main(void)
+{
+  return StubUse();
+}
diff --git a/Tests/RunCMake/RuntimePath/StubUse.c b/Tests/RunCMake/RuntimePath/StubUse.c
new file mode 100644
index 0000000..ffdaf6d
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/StubUse.c
@@ -0,0 +1,5 @@
+extern int Stub(void);
+int StubUse(void)
+{
+  return Stub();
+}
diff --git a/Tests/RunCMake/export/DependOnDoubleExport-stderr.txt b/Tests/RunCMake/export/DependOnDoubleExport-stderr.txt
index e8f8a09..a884939 100644
--- a/Tests/RunCMake/export/DependOnDoubleExport-stderr.txt
+++ b/Tests/RunCMake/export/DependOnDoubleExport-stderr.txt
@@ -1,7 +1,7 @@
 CMake Error in CMakeLists.txt:
   export called with target "exported" which requires target "doubleexported"
-  that is not in this export set, but in multiple other export sets:
-  .*/Tests/RunCMake/export/DependOnDoubleExport-build/exportset.cmake,
+  that is not in this export set, but in multiple other export sets:.*
+  .*/Tests/RunCMake/export/DependOnDoubleExport-build/exportset.cmake,.*
   .*/Tests/RunCMake/export/DependOnDoubleExport-build/manual.cmake.
 +
   An exported target cannot depend upon another target which is exported