Merge topic 'vector-reserve-and-emplace'

abc8410ac7 cmInstallScriptHandler: Reserve and emplace vector entries

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !9753
diff --git a/.gitlab/ci/ctest_exclusions.cmake b/.gitlab/ci/ctest_exclusions.cmake
index ed5e1dd..a2789c3 100644
--- a/.gitlab/ci/ctest_exclusions.cmake
+++ b/.gitlab/ci/ctest_exclusions.cmake
@@ -34,13 +34,6 @@
     )
 endif()
 
-if ("$ENV{CMAKE_CONFIGURATION}" STREQUAL "windows_vs2022_x64_ninja")
-  list(APPEND test_exclusions
-    # FIXME(#25573): This test failure needs further investigation.
-    "^SwiftMixLib$"
-    )
-endif()
-
 string(REPLACE ";" "|" test_exclusions "${test_exclusions}")
 if (test_exclusions)
   set(test_exclusions "(${test_exclusions})")
diff --git a/.gitlab/ci/docker/ninja/centos7-aarch64.bash b/.gitlab/ci/docker/ninja/centos7-aarch64.bash
deleted file mode 100755
index 4052f29..0000000
--- a/.gitlab/ci/docker/ninja/centos7-aarch64.bash
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -x
-
-cleanup() {
-    docker container rm -fv "$build_container" >/dev/null 2>&1 || true
-    docker image rm -f "$build_image" >/dev/null 2>&1 || true
-}
-
-readonly suffix="-$(date -u +%Y-%m-%d)-${RANDOM}"
-readonly build_container="ninja-build-linux-aarch64$suffix"
-readonly build_image="ninja:build-linux-aarch64$suffix"
-readonly git_tag="${1-v1.11.0}"
-
-trap "cleanup" EXIT INT TERM
-
-docker image build --build-arg GIT_TAG="$git_tag" --tag="$build_image" "${BASH_SOURCE%/*}/centos7-aarch64"
-docker container create --name "$build_container" "$build_image"
-docker cp "$build_container:/ninja/ninja" "ninja"
diff --git a/.gitlab/ci/docker/ninja/centos7-aarch64/Dockerfile b/.gitlab/ci/docker/ninja/centos7-aarch64/Dockerfile
deleted file mode 100644
index 3fb13b0..0000000
--- a/.gitlab/ci/docker/ninja/centos7-aarch64/Dockerfile
+++ /dev/null
@@ -1,7 +0,0 @@
-FROM kitware/cmake:build-linux-aarch64-base-2020-12-21
-MAINTAINER Brad King <brad.king@kitware.com>
-
-ARG GIT_TAG=v1.11.0
-
-COPY build_ninja.sh /root/build_ninja.sh
-RUN scl enable devtoolset-7 -- sh /root/build_ninja.sh $GIT_TAG
diff --git a/.gitlab/ci/docker/ninja/centos7-aarch64/build_ninja.sh b/.gitlab/ci/docker/ninja/centos7-aarch64/build_ninja.sh
deleted file mode 100755
index 91fb2d4..0000000
--- a/.gitlab/ci/docker/ninja/centos7-aarch64/build_ninja.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-set -e
-
-git clone https://github.com/ninja-build/ninja.git
-cd ninja
-git checkout "${1-v1.11.0}"
-./configure.py --bootstrap
-./ninja all
-./ninja_test
-strip ninja
diff --git a/.gitlab/ci/ninja.ps1 b/.gitlab/ci/ninja.ps1
index 4c4d675..81d3f2e 100644
--- a/.gitlab/ci/ninja.ps1
+++ b/.gitlab/ci/ninja.ps1
@@ -5,9 +5,18 @@
     exit $LASTEXITCODE
 }
 
-$version = "1.11.0"
-$sha256sum = "D0EE3DA143211AA447E750085876C9B9D7BCDD637AB5B2C5B41349C617F22F3B"
-$filename = "ninja-win"
+$version = "1.12.1"
+
+if ("$env:PROCESSOR_ARCHITECTURE" -eq "AMD64") {
+    $sha256sum = "F550FEC705B6D6FF58F2DB3C374C2277A37691678D6ABA463ADCBB129108467A"
+    $filename = "ninja-win"
+} elseif ("$env:PROCESSOR_ARCHITECTURE" -eq "ARM64") {
+    $sha256sum = "79C96A50E0DEAFEC212CFA85AA57C6B74003F52D9D1673DDCD1EAB1C958C5900"
+    $filename = "ninja-winarm64"
+} else {
+    throw ('unknown PROCESSOR_ARCHITECTURE: ' + "$env:PROCESSOR_ARCHITECTURE")
+}
+
 $tarball = "$filename.zip"
 
 $outdir = $pwd.Path
diff --git a/.gitlab/ci/ninja.sh b/.gitlab/ci/ninja.sh
index 753596b..530feac 100755
--- a/.gitlab/ci/ninja.sh
+++ b/.gitlab/ci/ninja.sh
@@ -6,25 +6,23 @@
     exec .gitlab/ci/ninja-nightly.sh
 fi
 
-readonly version="1.11.0"
+readonly version="1.12.1"
 baseurl="https://github.com/ninja-build/ninja/releases/download/v$version"
 
 case "$(uname -s)-$(uname -m)" in
     Linux-x86_64)
         shatool="sha256sum"
-        sha256sum="9726e730d5b8599f82654dc80265e64a10a8a817552c34153361ed0c017f9f02"
+        sha256sum="6f98805688d19672bd699fbbfa2c2cf0fc054ac3df1f0e6a47664d963d530255"
         filename="ninja-linux"
         ;;
     Linux-aarch64)
         shatool="sha256sum"
-        sha256sum="b002eb77cfcef6d329cccf8b1cc7ad138302d6e19b5b76b10b4c4d38564b47b5"
-        # Use binary built by adjacent 'docker/ninja/centos7-aarch64.bash' script.
-        baseurl="https://cmake.org/files/dependencies"
-        filename="ninja-$version-1-linux-aarch64"
+        sha256sum="5c25c6570b0155e95fce5918cb95f1ad9870df5768653afe128db822301a05a1"
+        filename="ninja-linux-aarch64"
         ;;
     Darwin-*)
         shatool="shasum -a 256"
-        sha256sum="21915277db59756bfc61f6f281c1f5e3897760b63776fd3d360f77dd7364137f"
+        sha256sum="89a287444b5b3e98f88a945afa50ce937b8ffd1dcc59c555ad9b1baf855298c9"
         filename="ninja-mac"
         ;;
     *)
diff --git a/Help/command/file.rst b/Help/command/file.rst
index ede95a1..0ac49f4 100644
--- a/Help/command/file.rst
+++ b/Help/command/file.rst
@@ -1169,6 +1169,14 @@
 
   5. Otherwise, the dependency is unresolved.
 
+  .. versionchanged:: 3.31
+
+    Resolution of each encountered library file name occurs at most once
+    while processing a given root ELF file (executable or shared object).
+    If a library file name is encountered again in the dependency tree,
+    the original resolution is assumed.  This behavior more closely matches
+    the dynamic loader's behavior on Linux.
+
   On Windows platforms, library resolution works as follows:
 
   1. DLL dependency names are converted to lowercase for matching filters.
diff --git a/Help/release/dev/elf-lib-deps-resolve.rst b/Help/release/dev/elf-lib-deps-resolve.rst
new file mode 100644
index 0000000..f7866eb
--- /dev/null
+++ b/Help/release/dev/elf-lib-deps-resolve.rst
@@ -0,0 +1,5 @@
+elf-lib-deps-resolve
+--------------------
+
+* The :command:`file(GET_RUNTIME_DEPENDENCIES)` command was updated
+  to more closely match the dynamic loader's behavior on Linux.
diff --git a/Modules/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake
index 27b7ae8..696f7a3 100644
--- a/Modules/CheckCCompilerFlag.cmake
+++ b/Modules/CheckCCompilerFlag.cmake
@@ -27,6 +27,8 @@
 order to force the check to be re-evaluated, the variable named by
 ``<resultVar>`` must be manually removed from the cache.
 
+See also :command:`check_compiler_flag` for a more general command syntax.
+
 The compile and link commands can be influenced by setting any of the
 following variables prior to calling ``check_c_compiler_flag()``
 
diff --git a/Modules/CheckCSourceCompiles.cmake b/Modules/CheckCSourceCompiles.cmake
index c01b6cf..801cf17 100644
--- a/Modules/CheckCSourceCompiles.cmake
+++ b/Modules/CheckCSourceCompiles.cmake
@@ -28,6 +28,8 @@
   ``STATIC_LIBRARY``, the source is compiled but not linked. In any case, all
   functions must be declared as usual.
 
+  See also :command:`check_source_compiles` for a more general command syntax.
+
   See also :command:`check_source_runs` to run compiled source.
 
   The compile and link commands can be influenced by setting any of the
diff --git a/Modules/CheckCSourceRuns.cmake b/Modules/CheckCSourceRuns.cmake
index e06bcca..7a34ece 100644
--- a/Modules/CheckCSourceRuns.cmake
+++ b/Modules/CheckCSourceRuns.cmake
@@ -5,7 +5,7 @@
 CheckCSourceRuns
 ----------------
 
-Check if given C source compiles and links into an executable and can
+Check once if given C source compiles and links into an executable and can
 subsequently be run.
 
 .. command:: check_c_source_runs
@@ -14,18 +14,16 @@
 
     check_c_source_runs(<code> <resultVar>)
 
-  Check that the source supplied in ``<code>`` can be compiled as a C source
-  file, linked as an executable and then run. The ``<code>`` must contain at
-  least a ``main()`` function. If the ``<code>`` could be built and run
-  successfully, the internal cache variable specified by ``<resultVar>`` will
-  be set to 1, otherwise it will be set to an value that evaluates to boolean
-  false (e.g. an empty string or an error message).
+  Check once that the source supplied in ``<code>`` can be built, linked as an
+  executable, and then run. The ``<code>`` must contain at least a ``main()``
+  function.
 
-  The check is only performed once, with the result cached in the variable named
-  by ``<resultVar>``. Every subsequent CMake run will reuse this cached value
-  rather than performing the check again, even if the ``<code>`` changes. In
-  order to force the check to be re-evaluated, the variable named by
-  ``<resultVar>`` must be manually removed from the cache.
+  The result is stored in the internal cache variable specified by
+  ``<resultVar>``. Success of build and run is indicated by boolean ``true``.
+  Failure to build or run is indicated by boolean ``false`` such as an empty
+  string or an error message.
+
+  See also :command:`check_source_runs` for a more general command syntax.
 
   The compile and link commands can be influenced by setting any of the
   following variables prior to calling ``check_c_source_runs()``:
diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake
index 61ed640..90cd488 100644
--- a/Modules/CheckCXXCompilerFlag.cmake
+++ b/Modules/CheckCXXCompilerFlag.cmake
@@ -21,6 +21,8 @@
 issue a diagnostic message when given the flag.  Whether the flag has any
 effect or even a specific one is beyond the scope of this module.
 
+See also :command:`check_compiler_flag` for a more general command syntax.
+
 .. note::
   Since the :command:`try_compile` command forwards flags from variables
   like :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags
diff --git a/Modules/CheckCXXSourceCompiles.cmake b/Modules/CheckCXXSourceCompiles.cmake
index 7c03c4a..c9616d8 100644
--- a/Modules/CheckCXXSourceCompiles.cmake
+++ b/Modules/CheckCXXSourceCompiles.cmake
@@ -28,6 +28,8 @@
   ``STATIC_LIBRARY``, the source is compiled but not linked. In any case, all
   functions must be declared as usual.
 
+  See also :command:`check_source_compiles` for a more general command syntax.
+
   See also :command:`check_source_runs` to run compiled source.
 
   The compile and link commands can be influenced by setting any of the
diff --git a/Modules/CheckCXXSourceRuns.cmake b/Modules/CheckCXXSourceRuns.cmake
index eb643eb..0f14a3a 100644
--- a/Modules/CheckCXXSourceRuns.cmake
+++ b/Modules/CheckCXXSourceRuns.cmake
@@ -5,7 +5,7 @@
 CheckCXXSourceRuns
 ------------------
 
-Check if given C++ source compiles and links into an executable and can
+Check once if given C++ source compiles and links into an executable and can
 subsequently be run.
 
 .. command:: check_cxx_source_runs
@@ -14,18 +14,16 @@
 
     check_cxx_source_runs(<code> <resultVar>)
 
-  Check that the source supplied in ``<code>`` can be compiled as a C++ source
-  file, linked as an executable and then run. The ``<code>`` must contain at
-  least a ``main()`` function. If the ``<code>`` could be built and run
-  successfully, the internal cache variable specified by ``<resultVar>`` will
-  be set to 1, otherwise it will be set to an value that evaluates to boolean
-  false (e.g. an empty string or an error message).
+  Check once that the source supplied in ``<code>`` can be built, linked as an
+  executable, and then run. The ``<code>`` must contain at least a ``main()``
+  function.
 
-  The check is only performed once, with the result cached in the variable named
-  by ``<resultVar>``. Every subsequent CMake run will reuse this cached value
-  rather than performing the check again, even if the ``<code>`` changes. In
-  order to force the check to be re-evaluated, the variable named by
-  ``<resultVar>`` must be manually removed from the cache.
+  The result is stored in the internal cache variable specified by
+  ``<resultVar>``. Success of build and run is indicated by boolean ``true``.
+  Failure to build or run is indicated by boolean ``false`` such as an empty
+  string or an error message.
+
+  See also :command:`check_source_runs` for a more general command syntax.
 
   The compile and link commands can be influenced by setting any of the
   following variables prior to calling ``check_cxx_source_runs()``:
diff --git a/Modules/CheckFortranCompilerFlag.cmake b/Modules/CheckFortranCompilerFlag.cmake
index 81a2345..94090ef 100644
--- a/Modules/CheckFortranCompilerFlag.cmake
+++ b/Modules/CheckFortranCompilerFlag.cmake
@@ -29,6 +29,8 @@
 order to force the check to be re-evaluated, the variable named by
 ``<resultVar>`` must be manually removed from the cache.
 
+See also :command:`check_compiler_flag` for a more general command syntax.
+
 The compile and link commands can be influenced by setting any of the
 following variables prior to calling ``check_fortran_compiler_flag()``
 
diff --git a/Modules/CheckFortranSourceCompiles.cmake b/Modules/CheckFortranSourceCompiles.cmake
index 4cbe67a..e9545ab 100644
--- a/Modules/CheckFortranSourceCompiles.cmake
+++ b/Modules/CheckFortranSourceCompiles.cmake
@@ -30,6 +30,8 @@
   ``SRC_EXT`` option can be used to override this with ``.<extension>`` instead--
   ``.F90`` is a typical choice.
 
+  See also :command:`check_source_compiles` for a more general command syntax.
+
   See also :command:`check_source_runs` to run compiled source.
 
   Internally, :command:`try_compile` is used to compile the source. If
diff --git a/Modules/CheckFortranSourceRuns.cmake b/Modules/CheckFortranSourceRuns.cmake
index 9bf9fb2..97d750a 100644
--- a/Modules/CheckFortranSourceRuns.cmake
+++ b/Modules/CheckFortranSourceRuns.cmake
@@ -7,7 +7,7 @@
 
 .. versionadded:: 3.14
 
-Check if given Fortran source compiles and links into an executable and can
+Check once if given Fortran source compiles and links into an executable and can
 subsequently be run.
 
 .. command:: check_fortran_source_runs
@@ -17,9 +17,13 @@
     check_fortran_source_runs(<code> <resultVar>
         [SRC_EXT <extension>])
 
-  Check that the source supplied in ``<code>`` can be compiled as a Fortran source
-  file, linked as an executable and then run. The ``<code>`` must be a Fortran
-  ``program``.
+  Check once that the source supplied in ``<code>`` can be built, linked as an
+  executable, and then run. The ``<code>`` must contain a Fortran ``program``.
+
+  The result is stored in the internal cache variable specified by
+  ``<resultVar>``. Success of build and run is indicated by boolean ``true``.
+  Failure to build or run is indicated by boolean ``false`` such as an empty
+  string or an error message.
 
   .. code-block:: cmake
 
@@ -29,25 +33,10 @@
     end program"
     HAVE_COARRAY)
 
-  This command can help avoid costly build processes when a compiler lacks support
-  for a necessary feature, or a particular vendor library is not compatible with
-  the Fortran compiler version being used. Some of these failures only occur at runtime
-  instead of linktime, and a trivial runtime example can catch the issue before the
-  main build process.
-
-  If the ``<code>`` could be built and run
-  successfully, the internal cache variable specified by ``<resultVar>`` will
-  be set to 1, otherwise it will be set to an value that evaluates to boolean
-  false (e.g. an empty string or an error message).
-
   By default, the test source file will be given a ``.F90`` file extension. The
   ``SRC_EXT`` option can be used to override this with ``.<extension>`` instead.
 
-  The check is only performed once, with the result cached in the variable named
-  by ``<resultVar>``. Every subsequent CMake run will reuse this cached value
-  rather than performing the check again, even if the ``<code>`` changes. In
-  order to force the check to be re-evaluated, the variable named by
-  ``<resultVar>`` must be manually removed from the cache.
+  See also :command:`check_source_runs` for a more general command syntax.
 
   The compile and link commands can be influenced by setting any of the
   following variables prior to calling ``check_fortran_source_runs()``:
diff --git a/Modules/CheckOBJCCompilerFlag.cmake b/Modules/CheckOBJCCompilerFlag.cmake
index f6d259e..f87949b 100644
--- a/Modules/CheckOBJCCompilerFlag.cmake
+++ b/Modules/CheckOBJCCompilerFlag.cmake
@@ -29,6 +29,8 @@
 order to force the check to be re-evaluated, the variable named by
 ``<resultVar>`` must be manually removed from the cache.
 
+See also :command:`check_compiler_flag` for a more general command syntax.
+
 The compile and link commands can be influenced by setting any of the
 following variables prior to calling ``check_objc_compiler_flag()``
 
diff --git a/Modules/CheckOBJCSourceCompiles.cmake b/Modules/CheckOBJCSourceCompiles.cmake
index c6e09db..1158b91 100644
--- a/Modules/CheckOBJCSourceCompiles.cmake
+++ b/Modules/CheckOBJCSourceCompiles.cmake
@@ -30,6 +30,8 @@
   ``STATIC_LIBRARY``, the source is compiled but not linked. In any case, all
   functions must be declared as usual.
 
+  See also :command:`check_source_compiles` for a more general command syntax.
+
   See also :command:`check_source_runs` to run compiled source.
 
   The compile and link commands can be influenced by setting any of the
diff --git a/Modules/CheckOBJCSourceRuns.cmake b/Modules/CheckOBJCSourceRuns.cmake
index 511cac6..6b8160d 100644
--- a/Modules/CheckOBJCSourceRuns.cmake
+++ b/Modules/CheckOBJCSourceRuns.cmake
@@ -7,8 +7,8 @@
 
 .. versionadded:: 3.16
 
-Check if given Objective-C source compiles and links into an executable and can
-subsequently be run.
+Check once if given Objective-C source compiles and links into an executable and
+can subsequently be run.
 
 .. command:: check_objc_source_runs
 
@@ -16,18 +16,16 @@
 
     check_objc_source_runs(<code> <resultVar>)
 
-  Check that the source supplied in ``<code>`` can be compiled as a Objective-C source
-  file, linked as an executable and then run. The ``<code>`` must contain at
-  least a ``main()`` function. If the ``<code>`` could be built and run
-  successfully, the internal cache variable specified by ``<resultVar>`` will
-  be set to 1, otherwise it will be set to an value that evaluates to boolean
-  false (e.g. an empty string or an error message).
+  Check once that the source supplied in ``<code>`` can be built, linked as an
+  executable, and then run. The ``<code>`` must contain at least a ``main()``
+  function.
 
-  The check is only performed once, with the result cached in the variable named
-  by ``<resultVar>``. Every subsequent CMake run will reuse this cached value
-  rather than performing the check again, even if the ``<code>`` changes. In
-  order to force the check to be re-evaluated, the variable named by
-  ``<resultVar>`` must be manually removed from the cache.
+  The result is stored in the internal cache variable specified by
+  ``<resultVar>``. Success of build and run is indicated by boolean ``true``.
+  Failure to build or run is indicated by boolean ``false`` such as an empty
+  string or an error message.
+
+  See also :command:`check_source_runs` for a more general command syntax.
 
   The compile and link commands can be influenced by setting any of the
   following variables prior to calling ``check_objc_source_runs()``
diff --git a/Modules/CheckOBJCXXCompilerFlag.cmake b/Modules/CheckOBJCXXCompilerFlag.cmake
index 32d50c9..5091a75 100644
--- a/Modules/CheckOBJCXXCompilerFlag.cmake
+++ b/Modules/CheckOBJCXXCompilerFlag.cmake
@@ -29,6 +29,8 @@
 order to force the check to be re-evaluated, the variable named by
 ``<resultVar>`` must be manually removed from the cache.
 
+See also :command:`check_compiler_flag` for a more general command syntax.
+
 The compile and link commands can be influenced by setting any of the
 following variables prior to calling ``check_objcxx_compiler_flag()``
 
diff --git a/Modules/CheckOBJCXXSourceCompiles.cmake b/Modules/CheckOBJCXXSourceCompiles.cmake
index 4a18c21..af3ffde 100644
--- a/Modules/CheckOBJCXXSourceCompiles.cmake
+++ b/Modules/CheckOBJCXXSourceCompiles.cmake
@@ -30,6 +30,8 @@
   ``STATIC_LIBRARY``, the source is compiled but not linked. In any case, all
   functions must be declared as usual.
 
+  See also :command:`check_source_compiles` for a more general command syntax.
+
   See also :command:`check_source_runs` to run compiled source.
 
   The compile and link commands can be influenced by setting any of the
diff --git a/Modules/CheckOBJCXXSourceRuns.cmake b/Modules/CheckOBJCXXSourceRuns.cmake
index 49db3cb..f867ac3 100644
--- a/Modules/CheckOBJCXXSourceRuns.cmake
+++ b/Modules/CheckOBJCXXSourceRuns.cmake
@@ -7,8 +7,8 @@
 
 .. versionadded:: 3.16
 
-Check if given Objective-C++ source compiles and links into an executable and can
-subsequently be run.
+Check once if given Objective-C++ source compiles and links into an executable
+and can subsequently be run.
 
 .. command:: check_objcxx_source_runs
 
@@ -16,18 +16,16 @@
 
     check_objcxx_source_runs(<code> <resultVar>)
 
-  Check that the source supplied in ``<code>`` can be compiled as a Objective-C++ source
-  file, linked as an executable and then run. The ``<code>`` must contain at
-  least a ``main()`` function. If the ``<code>`` could be built and run
-  successfully, the internal cache variable specified by ``<resultVar>`` will
-  be set to 1, otherwise it will be set to an value that evaluates to boolean
-  false (e.g. an empty string or an error message).
+  Check once that the source supplied in ``<code>`` can be built, linked as an
+  executable, and then run. The ``<code>`` must contain at least a ``main()``
+  function.
 
-  The check is only performed once, with the result cached in the variable named
-  by ``<resultVar>``. Every subsequent CMake run will reuse this cached value
-  rather than performing the check again, even if the ``<code>`` changes. In
-  order to force the check to be re-evaluated, the variable named by
-  ``<resultVar>`` must be manually removed from the cache.
+  The result is stored in the internal cache variable specified by
+  ``<resultVar>``. Success of build and run is indicated by boolean ``true``.
+  Failure to build or run is indicated by boolean ``false`` such as an empty
+  string or an error message.
+
+  See also :command:`check_source_runs` for a more general command syntax.
 
   The compile and link commands can be influenced by setting any of the
   following variables prior to calling ``check_objcxx_source_runs()``
diff --git a/Modules/CheckSourceRuns.cmake b/Modules/CheckSourceRuns.cmake
index 75636f4..84684b6 100644
--- a/Modules/CheckSourceRuns.cmake
+++ b/Modules/CheckSourceRuns.cmake
@@ -18,12 +18,14 @@
     check_source_runs(<lang> <code> <resultVar>
                       [SRC_EXT <extension>])
 
-  Check that the source supplied in ``<code>`` can be compiled as a source
-  file for the requested language, linked as an executable and then run.
-  If the ``<code>`` could be built and run successfully, the internal cache variable
-  specified by ``<resultVar>`` will be set to 1, otherwise it will be set to
-  a value that evaluates to boolean false (e.g. an empty string or an error
-  message).
+  Check once that the ``<lang>`` source supplied in ``<code>`` can be built,
+  linked as an executable, and then run. The ``<code>`` must contain at least
+  a ``main()`` function, or in Fortran a ``program``.
+
+  The result is stored in the internal cache variable specified by
+  ``<resultVar>``. Success of build and run is indicated by boolean ``true``.
+  Failure to build or run is indicated by boolean ``false`` such as an empty
+  string or an error message.
 
   By default, the test source file will be given a file extension that matches
   the requested language. The ``SRC_EXT`` option can be used to override this
@@ -47,12 +49,6 @@
     end program"
     HAVE_COARRAY)
 
-  The check is only performed once, with the result cached in the variable named
-  by ``<resultVar>``. Every subsequent CMake run will reuse this cached value
-  rather than performing the check again, even if the ``<code>`` changes. In
-  order to force the check to be re-evaluated, the variable named by
-  ``<resultVar>`` must be manually removed from the cache.
-
   The compile and link commands can be influenced by setting any of the
   following variables prior to calling ``check_source_runs()``
 
diff --git a/Modules/FindJNI.cmake b/Modules/FindJNI.cmake
index 51f05b9..82e3d88 100644
--- a/Modules/FindJNI.cmake
+++ b/Modules/FindJNI.cmake
@@ -391,8 +391,10 @@
     execute_process(
       COMMAND xcodebuild -version
       OUTPUT_VARIABLE _FindJNI_XCODEBUILD_VERSION
+      ERROR_VARIABLE _FindJNI_XCODEBUILD_VERSION
+      RESULT_VARIABLE _FindJNI_XCODEBUILD_RESULT
       )
-    if(_FindJNI_XCODEBUILD_VERSION MATCHES "Xcode ([0-9]+(\\.[0-9]+)*)")
+    if(_FindJNI_XCODEBUILD_RESULT EQUAL 0 AND _FindJNI_XCODEBUILD_VERSION MATCHES "Xcode ([0-9]+(\\.[0-9]+)*)")
       set(_FindJNI_XCODE_VERSION "${CMAKE_MATCH_1}")
     else()
       set(_FindJNI_XCODE_VERSION "")
diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake
index b42a85e..88aaf96 100644
--- a/Modules/FindwxWidgets.cmake
+++ b/Modules/FindwxWidgets.cmake
@@ -467,7 +467,7 @@
       list(APPEND wxWidgets_LIBRARIES imm32)
     endif()
 
-    list(APPEND wxWidgets_LIBRARIES winmm comctl32 uuid oleacc uxtheme rpcrt4 shlwapi version wsock32)
+    list(APPEND wxWidgets_LIBRARIES gdiplus msimg32 winmm comctl32 uuid oleacc uxtheme rpcrt4 shlwapi version wsock32)
   endmacro()
 
   #-------------------------------------------------------------------
diff --git a/Modules/Internal/CMakeSwiftLinkerInformation.cmake b/Modules/Internal/CMakeSwiftLinkerInformation.cmake
index fb3e986..6d1881f 100644
--- a/Modules/Internal/CMakeSwiftLinkerInformation.cmake
+++ b/Modules/Internal/CMakeSwiftLinkerInformation.cmake
@@ -13,7 +13,7 @@
 set(_INCLUDED_FILE 0)
 
 # Load linker-specific information.
-if(CMAKE_Swoft_COMPILER_LINKER_ID)
+if(CMAKE_Swift_COMPILER_LINKER_ID)
   include(Linker/${CMAKE_Swift_COMPILER_LINKER_ID}-Swift OPTIONAL)
 endif()
 
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 80323b9..d4ad8e6 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 30)
-set(CMake_VERSION_PATCH 20240819)
+set(CMake_VERSION_PATCH 20240820)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 03b8766..b025570 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -1552,6 +1552,7 @@
 #ifdef _WIN32
     // Given name matches a reserved name (on Windows)?
     // Then return it prepended with an underscore.
+    // See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
     cmsys::RegularExpression reserved_pattern("^("
                                               "[Cc][Oo][Nn]|"
                                               "[Pp][Rr][Nn]|"
@@ -1559,7 +1560,7 @@
                                               "[Nn][Uu][Ll]|"
                                               "[Cc][Oo][Mm][1-9]|"
                                               "[Ll][Pp][Tt][1-9]"
-                                              ")([.].+)?");
+                                              ")[.]?$");
     if (reserved_pattern.find(name)) {
       return "_" + name;
     }
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 43b1d76..155bc9e 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -863,8 +863,8 @@
     /* clang-format on */
     componentCode += out.str();
   } else {
-    componentCode +=
-      "  File /r \"${INST_DIR}\\" + component->Name + "\\*.*\"\n";
+    componentCode += "  File /r \"${INST_DIR}\\" +
+      this->GetSanitizedDirOrFileName(component->Name) + "\\*.*\"\n";
   }
   componentCode += "SectionEnd\n";
 
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index 39a8e85..305ac56 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -583,7 +583,7 @@
               cmValue projVersionPatch =
                 mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
               std::ostringstream ostr;
-              ostr << *projVersionMajor << "." << *projVersionMinor << '.'
+              ostr << *projVersionMajor << '.' << *projVersionMinor << '.'
                    << *projVersionPatch;
               mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str());
             }
diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx
index e2a8f92..ca40726 100644
--- a/Source/cmBinUtilsLinuxELFLinker.cxx
+++ b/Source/cmBinUtilsLinuxELFLinker.cxx
@@ -3,7 +3,10 @@
 
 #include "cmBinUtilsLinuxELFLinker.h"
 
+#include <queue>
 #include <sstream>
+#include <unordered_set>
+#include <utility>
 
 #include <cm/memory>
 #include <cm/string_view>
@@ -89,8 +92,6 @@
 bool cmBinUtilsLinuxELFLinker::ScanDependencies(
   std::string const& file, cmStateEnums::TargetType /* unused */)
 {
-  std::vector<std::string> parentRpaths;
-
   cmELF elf(file.c_str());
   if (!elf) {
     return false;
@@ -106,40 +107,53 @@
     }
   }
 
-  return this->ScanDependencies(file, parentRpaths);
+  return this->ScanDependencies(file);
 }
 
-bool cmBinUtilsLinuxELFLinker::ScanDependencies(
-  std::string const& file, std::vector<std::string> const& parentRpaths)
+bool cmBinUtilsLinuxELFLinker::ScanDependencies(std::string const& mainFile)
 {
-  std::string origin = cmSystemTools::GetFilenamePath(file);
-  std::vector<std::string> needed;
-  std::vector<std::string> rpaths;
-  std::vector<std::string> runpaths;
-  if (!this->Tool->GetFileInfo(file, needed, rpaths, runpaths)) {
-    return false;
-  }
-  for (auto& runpath : runpaths) {
-    runpath = ReplaceOrigin(runpath, origin);
-  }
-  for (auto& rpath : rpaths) {
-    rpath = ReplaceOrigin(rpath, origin);
-  }
+  std::unordered_set<std::string> resolvedDependencies;
+  std::queue<std::pair<std::string, std::vector<std::string>>> queueToResolve;
+  queueToResolve.push(std::make_pair(mainFile, std::vector<std::string>{}));
 
-  std::vector<std::string> searchPaths;
-  if (!runpaths.empty()) {
-    searchPaths = runpaths;
-  } else {
-    searchPaths = rpaths;
-    searchPaths.insert(searchPaths.end(), parentRpaths.begin(),
-                       parentRpaths.end());
-  }
+  while (!queueToResolve.empty()) {
+    std::string file = std::move(queueToResolve.front().first);
+    std::vector<std::string> parentRpaths =
+      std::move(queueToResolve.front().second);
+    queueToResolve.pop();
 
-  searchPaths.insert(searchPaths.end(), this->LDConfigPaths.begin(),
-                     this->LDConfigPaths.end());
+    std::string origin = cmSystemTools::GetFilenamePath(file);
+    std::vector<std::string> needed;
+    std::vector<std::string> rpaths;
+    std::vector<std::string> runpaths;
+    if (!this->Tool->GetFileInfo(file, needed, rpaths, runpaths)) {
+      return false;
+    }
+    for (auto& runpath : runpaths) {
+      runpath = ReplaceOrigin(runpath, origin);
+    }
+    for (auto& rpath : rpaths) {
+      rpath = ReplaceOrigin(rpath, origin);
+    }
 
-  for (auto const& dep : needed) {
-    if (!this->Archive->IsPreExcluded(dep)) {
+    std::vector<std::string> searchPaths;
+    if (!runpaths.empty()) {
+      searchPaths = runpaths;
+    } else {
+      searchPaths = rpaths;
+      searchPaths.insert(searchPaths.end(), parentRpaths.begin(),
+                         parentRpaths.end());
+    }
+
+    searchPaths.insert(searchPaths.end(), this->LDConfigPaths.begin(),
+                       this->LDConfigPaths.end());
+
+    for (auto const& dep : needed) {
+      if (resolvedDependencies.count(dep) != 0 ||
+          this->Archive->IsPreExcluded(dep)) {
+        continue;
+      }
+
       std::string path;
       bool resolved = false;
       if (dep.find('/') != std::string::npos) {
@@ -150,6 +164,7 @@
         return false;
       }
       if (resolved) {
+        resolvedDependencies.emplace(dep);
         if (!this->Archive->IsPostExcluded(path)) {
           bool unique;
           this->Archive->AddResolvedPath(dep, path, unique);
@@ -157,9 +172,8 @@
             std::vector<std::string> combinedParentRpaths = parentRpaths;
             combinedParentRpaths.insert(combinedParentRpaths.end(),
                                         rpaths.begin(), rpaths.end());
-            if (!this->ScanDependencies(path, combinedParentRpaths)) {
-              return false;
-            }
+
+            queueToResolve.push(std::make_pair(path, combinedParentRpaths));
           }
         }
       } else {
diff --git a/Source/cmBinUtilsLinuxELFLinker.h b/Source/cmBinUtilsLinuxELFLinker.h
index 395ed56..0b0d8b5 100644
--- a/Source/cmBinUtilsLinuxELFLinker.h
+++ b/Source/cmBinUtilsLinuxELFLinker.h
@@ -34,8 +34,7 @@
   std::vector<std::string> LDConfigPaths;
   std::uint16_t Machine = 0;
 
-  bool ScanDependencies(std::string const& file,
-                        std::vector<std::string> const& parentRpaths);
+  bool ScanDependencies(std::string const& mainFile);
 
   bool ResolveDependency(std::string const& name,
                          std::vector<std::string> const& searchPaths,
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index f42d7f6..7d51dd1 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -235,8 +235,8 @@
   char buf[1024];
   // add todays year day and month to the time in str because
   // curl_getdate no longer assumes the day is today
-  snprintf(buf, sizeof(buf), "%d%02d%02d %s", lctime->tm_year + 1900,
-           lctime->tm_mon + 1, lctime->tm_mday, str.c_str());
+  std::snprintf(buf, sizeof(buf), "%d%02d%02d %s", lctime->tm_year + 1900,
+                lctime->tm_mon + 1, lctime->tm_mday, str.c_str());
   cmCTestLog(this, OUTPUT,
              "Determine Nightly Start Time" << std::endl
                                             << "   Specified time: " << str
@@ -1074,11 +1074,6 @@
   return cmCTest::EXPERIMENTAL;
 }
 
-// ######################################################################
-// ######################################################################
-// ######################################################################
-// ######################################################################
-
 bool cmCTest::RunMakeCommand(const std::string& command, std::string& output,
                              int* retVal, const char* dir, cmDuration timeout,
                              std::ostream& ofs, Encoding encoding)
@@ -1191,11 +1186,6 @@
   return true;
 }
 
-// ######################################################################
-// ######################################################################
-// ######################################################################
-// ######################################################################
-
 bool cmCTest::RunTest(const std::vector<std::string>& argv,
                       std::string* output, int* retVal, std::ostream* log,
                       cmDuration testTimeOut,
@@ -1857,22 +1847,20 @@
 void cmCTest::ErrorMessageUnknownDashDValue(std::string& val)
 {
   cmCTestLog(this, ERROR_MESSAGE,
-             "CTest -D called with incorrect option: " << val << std::endl);
+             "CTest -D called with incorrect option: " << val << '\n');
 
-  cmCTestLog(
-    this, ERROR_MESSAGE,
-    "Available options are:"
-      << std::endl
-      << "  ctest -D Continuous" << std::endl
-      << "  ctest -D Continuous(Start|Update|Configure|Build)" << std::endl
-      << "  ctest -D Continuous(Test|Coverage|MemCheck|Submit)" << std::endl
-      << "  ctest -D Experimental" << std::endl
-      << "  ctest -D Experimental(Start|Update|Configure|Build)" << std::endl
-      << "  ctest -D Experimental(Test|Coverage|MemCheck|Submit)" << std::endl
-      << "  ctest -D Nightly" << std::endl
-      << "  ctest -D Nightly(Start|Update|Configure|Build)" << std::endl
-      << "  ctest -D Nightly(Test|Coverage|MemCheck|Submit)" << std::endl
-      << "  ctest -D NightlyMemoryCheck" << std::endl);
+  cmCTestLog(this, ERROR_MESSAGE,
+             "Available options are:\n"
+             "  ctest -D Continuous\n"
+             "  ctest -D Continuous(Start|Update|Configure|Build)\n"
+             "  ctest -D Continuous(Test|Coverage|MemCheck|Submit)\n"
+             "  ctest -D Experimental\n"
+             "  ctest -D Experimental(Start|Update|Configure|Build)\n"
+             "  ctest -D Experimental(Test|Coverage|MemCheck|Submit)\n"
+             "  ctest -D Nightly\n"
+             "  ctest -D Nightly(Start|Update|Configure|Build)\n"
+             "  ctest -D Nightly(Test|Coverage|MemCheck|Submit)\n"
+             "  ctest -D NightlyMemoryCheck\n");
 }
 
 bool cmCTest::CheckArgument(const std::string& arg, cm::string_view varg1,
@@ -1982,7 +1970,7 @@
       this->SetTestLoad(load);
     } else {
       cmCTestLog(this, WARNING,
-                 "Invalid value for 'Test Load' : " << args[i] << std::endl);
+                 "Invalid value for 'Test Load' : " << args[i] << '\n');
     }
   }
 
@@ -2908,21 +2896,21 @@
     if (!this->SetTest(args[i], false)) {
       success = false;
       cmCTestLog(this, ERROR_MESSAGE,
-                 "CTest -T called with incorrect option: " << args[i]
-                                                           << std::endl);
+                 "CTest -T called with incorrect option: " << args[i] << '\n');
+      /* clang-format off */
       cmCTestLog(this, ERROR_MESSAGE,
-                 "Available options are:"
-                   << std::endl
-                   << "  " << ctestExec << " -T all" << std::endl
-                   << "  " << ctestExec << " -T start" << std::endl
-                   << "  " << ctestExec << " -T update" << std::endl
-                   << "  " << ctestExec << " -T configure" << std::endl
-                   << "  " << ctestExec << " -T build" << std::endl
-                   << "  " << ctestExec << " -T test" << std::endl
-                   << "  " << ctestExec << " -T coverage" << std::endl
-                   << "  " << ctestExec << " -T memcheck" << std::endl
-                   << "  " << ctestExec << " -T notes" << std::endl
-                   << "  " << ctestExec << " -T submit" << std::endl);
+                 "Available options are:\n"
+                 "  " << ctestExec << " -T all\n"
+                 "  " << ctestExec << " -T start\n"
+                 "  " << ctestExec << " -T update\n"
+                 "  " << ctestExec << " -T configure\n"
+                 "  " << ctestExec << " -T build\n"
+                 "  " << ctestExec << " -T test\n"
+                 "  " << ctestExec << " -T coverage\n"
+                 "  " << ctestExec << " -T memcheck\n"
+                 "  " << ctestExec << " -T notes\n"
+                 "  " << ctestExec << " -T submit\n");
+      /* clang-format on */
     }
   }
   return success;
@@ -2948,14 +2936,14 @@
     } else {
       success = false;
       cmCTestLog(this, ERROR_MESSAGE,
-                 "CTest -M called with incorrect option: " << str
-                                                           << std::endl);
+                 "CTest -M called with incorrect option: " << str << '\n');
+      /* clang-format off */
       cmCTestLog(this, ERROR_MESSAGE,
-                 "Available options are:"
-                   << std::endl
-                   << "  " << ctestExec << " -M Continuous" << std::endl
-                   << "  " << ctestExec << " -M Experimental" << std::endl
-                   << "  " << ctestExec << " -M Nightly" << std::endl);
+                 "Available options are:\n"
+                 "  " << ctestExec << " -M Continuous\n"
+                 "  " << ctestExec << " -M Experimental\n"
+                 "  " << ctestExec << " -M Nightly\n");
+      /* clang-format on */
     }
   }
   return success;
@@ -3497,10 +3485,10 @@
   size_t epos = overStr.find('=');
   if (epos == std::string::npos) {
     cmCTestLog(this, ERROR_MESSAGE,
-               "CTest configuration overwrite specified in the wrong format."
-                 << std::endl
-                 << "Valid format is: --overwrite key=value" << std::endl
-                 << "The specified was: --overwrite " << overStr << std::endl);
+               "CTest configuration overwrite specified in the wrong format.\n"
+               "Valid format is: --overwrite key=value\n"
+               "The specified was: --overwrite "
+                 << overStr << '\n');
     return;
   }
   std::string key = overStr.substr(0, epos);
diff --git a/Source/cmString.hxx b/Source/cmString.hxx
index 1994c2c..5e1b524 100644
--- a/Source/cmString.hxx
+++ b/Source/cmString.hxx
@@ -518,7 +518,7 @@
     *this = std::move(s);
   }
 
-  void swap(String& other)
+  void swap(String& other) noexcept
   {
     std::swap(this->string_, other.string_);
     std::swap(this->view_, other.view_);
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index d030c48..bb80204 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -812,7 +812,7 @@
   std::ostringstream oss;
   for (auto i = 0u; i < parsedPermissions.size(); i++) {
     if (i != 0) {
-      oss << ";";
+      oss << ';';
     }
     oss << parsedPermissions[i];
   }
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 25b2ced..eaff8ef 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -60,7 +60,6 @@
 #include <cstring>
 #include <iostream>
 #include <memory>
-#include <sstream>
 #include <utility>
 
 #ifdef _WIN32
@@ -81,101 +80,89 @@
                              std::vector<std::string>::const_iterator argEnd);
 
 namespace {
+// ATTENTION If you add new commands, change here,
+// and in `cmakemain.cxx` in the options table
+const char* const HELP_AVAILABLE_COMMANDS = R"(Available commands:
+  capabilities              - Report capabilities built into cmake in JSON format
+  cat [--] <files>...       - concat the files and print them to the standard output
+  chdir dir cmd [args...]   - run command in a given directory
+  compare_files [--ignore-eol] file1 file2
+                              - check if file1 is same as file2
+  copy <file>... destination  - copy files to destination (either file or directory)
+  copy_directory <dir>... destination   - copy content of <dir>... directories to 'destination' directory
+  copy_directory_if_different <dir>... destination   - copy changed content of <dir>... directories to 'destination' directory
+  copy_if_different <file>... destination  - copy files if it has changed
+  echo [<string>...]        - displays arguments as text
+  echo_append [<string>...] - displays arguments as text but no new line
+  env [--unset=NAME ...] [NAME=VALUE ...] [--] <command> [<arg>...]
+                            - run command in a modified environment
+  environment               - display the current environment
+  make_directory <dir>...   - create parent and <dir> directories
+  md5sum <file>...          - create MD5 checksum of files
+  sha1sum <file>...         - create SHA1 checksum of files
+  sha224sum <file>...       - create SHA224 checksum of files
+  sha256sum <file>...       - create SHA256 checksum of files
+  sha384sum <file>...       - create SHA384 checksum of files
+  sha512sum <file>...       - create SHA512 checksum of files
+  remove [-f] <file>...     - remove the file(s), use -f to force it (deprecated: use rm instead)
+  remove_directory <dir>... - remove directories and their contents (deprecated: use rm instead)
+  rename oldname newname    - rename a file or directory (on one volume)
+  rm [-rRf] [--] <file/dir>... - remove files or directories, use -f to force it, r or R to remove directories and their contents recursively
+  sleep <number>...         - sleep for given number of seconds
+  tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]
+                            - create or extract a tar or zip archive
+  time command [args...]    - run command and display elapsed time
+  touch <file>...           - touch a <file>.
+  touch_nocreate <file>...  - touch a <file> but do not create it.
+  create_symlink old new    - create a symbolic link new -> old
+  create_hardlink old new   - create a hard link new -> old
+  true                      - do nothing with an exit code of 0
+  false                     - do nothing with an exit code of 1
+)";
+#if defined(_WIN32) && !defined(__CYGWIN__)
+const char* const HELP_AVAILABLE_WINDOWS_COMMANDS =
+  R"(Available on Windows only:
+  delete_regv key           - delete registry value
+  env_vs8_wince sdkname     - displays a batch file which sets the environment for the provided Windows CE SDK installed in VS2005
+  env_vs9_wince sdkname     - displays a batch file which sets the environment for the provided Windows CE SDK installed in VS2008
+  write_regv key value      - write registry value
+)";
+#endif
+
 void CMakeCommandUsage(std::string const& program)
 {
-  std::ostringstream errorStream;
-
+  /* clang-format off */
+  std::string help_screen = cmStrCat(
 #ifndef CMAKE_BOOTSTRAP
-  /* clang-format off */
-  errorStream
-    << "cmake version " << cmVersion::GetCMakeVersion() << "\n";
-/* clang-format on */
+    "cmake version "
+  , cmVersion::GetCMakeVersion()
+  , "\n"
 #else
-  /* clang-format off */
-  errorStream
-    << "cmake bootstrap\n";
-/* clang-format on */
+    "cmake bootstrap\n"
 #endif
-  // If you add new commands, change here,
-  // and in cmakemain.cxx in the options table
-  /* clang-format off */
-  errorStream
-    << "Usage: " << program << " -E <command> [arguments...]\n"
-    << "Available commands: \n"
-    << "  capabilities              - Report capabilities built into cmake "
-       "in JSON format\n"
-    << "  cat [--] <files>...       - concat the files and print them to the "
-       "standard output\n"
-    << "  chdir dir cmd [args...]   - run command in a given directory\n"
-    << "  compare_files [--ignore-eol] file1 file2\n"
-    << "                              - check if file1 is same as file2\n"
-    << "  copy <file>... destination  - copy files to destination "
-       "(either file or directory)\n"
-    << "  copy_directory <dir>... destination   - copy content of <dir>... "
-       "directories to 'destination' directory\n"
-    << "  copy_directory_if_different <dir>... destination   - copy changed content of <dir>... "
-       "directories to 'destination' directory\n"
-    << "  copy_if_different <file>... destination  - copy files if it has "
-       "changed\n"
-    << "  echo [<string>...]        - displays arguments as text\n"
-    << "  echo_append [<string>...] - displays arguments as text but no new "
-       "line\n"
-    << "  env [--unset=NAME ...] [NAME=VALUE ...] [--] <command> [<arg>...]\n"
-    << "                            - run command in a modified environment\n"
-    << "  environment               - display the current environment\n"
-    << "  make_directory <dir>...   - create parent and <dir> directories\n"
-    << "  md5sum <file>...          - create MD5 checksum of files\n"
-    << "  sha1sum <file>...         - create SHA1 checksum of files\n"
-    << "  sha224sum <file>...       - create SHA224 checksum of files\n"
-    << "  sha256sum <file>...       - create SHA256 checksum of files\n"
-    << "  sha384sum <file>...       - create SHA384 checksum of files\n"
-    << "  sha512sum <file>...       - create SHA512 checksum of files\n"
-    << "  remove [-f] <file>...     - remove the file(s), use -f to force "
-       "it (deprecated: use rm instead)\n"
-    << "  remove_directory <dir>... - remove directories and their contents (deprecated: use rm instead)\n"
-    << "  rename oldname newname    - rename a file or directory "
-       "(on one volume)\n"
-    << "  rm [-rRf] [--] <file/dir>... - remove files or directories, use -f "
-       "to force it, r or R to remove directories and their contents "
-       "recursively\n"
-    << "  sleep <number>...         - sleep for given number of seconds\n"
-    << "  tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
-    << "                            - create or extract a tar or zip archive\n"
-    << "  time command [args...]    - run command and display elapsed time\n"
-    << "  touch <file>...           - touch a <file>.\n"
-    << "  touch_nocreate <file>...  - touch a <file> but do not create it.\n"
-    << "  create_symlink old new    - create a symbolic link new -> old\n"
-    << "  create_hardlink old new   - create a hard link new -> old\n"
-    << "  true                      - do nothing with an exit code of 0\n"
-    << "  false                     - do nothing with an exit code of 1\n"
+    "Usage: "
+  , program
+  , " -E <command> [arguments...]\n"
+  , HELP_AVAILABLE_COMMANDS
 #if defined(_WIN32) && !defined(__CYGWIN__)
-    << "Available on Windows only:\n"
-    << "  delete_regv key           - delete registry value\n"
-    << "  env_vs8_wince sdkname     - displays a batch file which sets the "
-       "environment for the provided Windows CE SDK installed in VS2005\n"
-    << "  env_vs9_wince sdkname     - displays a batch file which sets the "
-       "environment for the provided Windows CE SDK installed in VS2008\n"
-    << "  write_regv key value      - write registry value\n"
+  , HELP_AVAILABLE_WINDOWS_COMMANDS
 #endif
-    ;
+  );
   /* clang-format on */
-
-  cmSystemTools::Error(errorStream.str());
+  cmSystemTools::Error(help_screen);
 }
 
 bool cmTarFilesFrom(std::string const& file, std::vector<std::string>& files)
 {
   if (cmSystemTools::FileIsDirectory(file)) {
-    std::ostringstream e;
-    e << "-E tar --files-from= file '" << file << "' is a directory";
-    cmSystemTools::Error(e.str());
+    cmSystemTools::Error(
+      cmStrCat("-E tar --files-from= file '", file, "' is a directory"));
     return false;
   }
   cmsys::ifstream fin(file.c_str());
   if (!fin) {
-    std::ostringstream e;
-    e << "-E tar --files-from= file '" << file << "' not found";
-    cmSystemTools::Error(e.str());
+    cmSystemTools::Error(
+      cmStrCat("-E tar --files-from= file '", file, "' not found"));
     return false;
   }
   std::string line;
@@ -186,10 +173,8 @@
     if (cmHasLiteralPrefix(line, "--add-file=")) {
       files.push_back(line.substr(11));
     } else if (cmHasLiteralPrefix(line, "-")) {
-      std::ostringstream e;
-      e << "-E tar --files-from='" << file << "' file invalid line:\n"
-        << line << "\n";
-      cmSystemTools::Error(e.str());
+      cmSystemTools::Error(cmStrCat("-E tar --files-from='", file,
+                                    "' file invalid line:\n", line, '\n'));
       return false;
     } else {
       files.push_back(line);
@@ -252,7 +237,7 @@
       cmSystemTools::ConvertToLongPath(path);
       this->DepFile << cmCMakePath(path).GenericString() << std::endl;
     } else {
-      this->Output << this->Line << std::endl << std::flush;
+      this->Output << this->Line << std::endl;
     }
 
     return true;
@@ -347,14 +332,14 @@
   int ret;
   if (!cmSystemTools::RunSingleCommand(iwyu_cmd, nullptr, &stdErr, &ret,
                                        nullptr, cmSystemTools::OUTPUT_NONE)) {
-    std::cerr << "Error running '" << iwyu_cmd[0] << "': " << stdErr << "\n";
+    std::cerr << "Error running '" << iwyu_cmd[0] << "': " << stdErr << '\n';
     return 1;
   }
   // Warn if iwyu reported anything.
   if (stdErr.find("should remove these lines:") != std::string::npos ||
       stdErr.find("should add these lines:") != std::string::npos) {
     std::cerr << "Warning: include-what-you-use reported diagnostics:\n"
-              << stdErr << "\n";
+              << stdErr << '\n';
   }
   // Older versions of iwyu always returned a non-zero exit code,
   // so ignore it unless the user has enabled errors.
@@ -403,7 +388,7 @@
   std::string stdErr;
   if (!cmSystemTools::RunSingleCommand(tidy_cmd, &stdOut, &stdErr, &ret,
                                        nullptr, cmSystemTools::OUTPUT_NONE)) {
-    std::cerr << "Error running '" << tidy_cmd[0] << "': " << stdErr << "\n";
+    std::cerr << "Error running '" << tidy_cmd[0] << "': " << stdErr << '\n';
     return 1;
   }
   // Output the stdout from clang-tidy to stderr
@@ -432,7 +417,7 @@
   int ret;
   if (!cmSystemTools::RunSingleCommand(lwyu_cmd, &stdOut, &stdErr, &ret,
                                        nullptr, cmSystemTools::OUTPUT_NONE)) {
-    std::cerr << "Error running '" << lwyu_cmd[0] << "': " << stdErr << "\n";
+    std::cerr << "Error running '" << lwyu_cmd[0] << "': " << stdErr << '\n';
     return 1;
   }
 
@@ -457,13 +442,13 @@
   if (!cmSystemTools::RunSingleCommand(cpplint_cmd, &stdOut, &stdOut, &ret,
                                        nullptr, cmSystemTools::OUTPUT_NONE)) {
     std::cerr << "Error running '" << cpplint_cmd[0] << "': " << stdOut
-              << "\n";
+              << '\n';
     return 1;
   }
   if (!stdOut.empty()) {
-    std::cerr << "Warning: cpplint diagnostics:\n";
-    // Output the output from cpplint to stderr
-    std::cerr << stdOut;
+    std::cerr << "Warning: cpplint diagnostics:\n"
+              // Output the output from cpplint to stderr
+              << stdOut;
   }
 
   // always return 0 so the build can continue as cpplint returns non-zero
@@ -503,7 +488,7 @@
   if (!cmSystemTools::RunSingleCommand(cppcheck_cmd, &stdOut, &stdErr, &ret,
                                        nullptr, cmSystemTools::OUTPUT_NONE)) {
     std::cerr << "Error running '" << cppcheck_cmd[0] << "': " << stdOut
-              << "\n";
+              << '\n';
     return 1;
   }
   std::cerr << stdOut;
@@ -593,7 +578,7 @@
         } else {
           // if it was not a co-compiler or --source/--launcher then error
           std::cerr << "__run_co_compile given unknown argument: " << arg
-                    << "\n";
+                    << '\n';
           return 1;
         }
       }
@@ -605,7 +590,7 @@
     std::cerr << "__run_co_compile missing command to run. "
                  "Looking for one or more of the following:\n";
     for (CoCompiler const& cc : CoCompilers) {
-      std::cerr << cc.Option << "\n";
+      std::cerr << cc.Option << '\n';
     }
     return 1;
   }
@@ -792,7 +777,7 @@
       }
       cmsys::ifstream fin(args[3].c_str(), std::ios::in | std::ios::binary);
       if (!fin) {
-        std::cerr << "could not open object list file: " << args[3] << "\n";
+        std::cerr << "could not open object list file: " << args[3] << '\n';
         return 1;
       }
       std::vector<std::string> files;
@@ -815,7 +800,7 @@
       }
       FILE* fout = cmsys::SystemTools::Fopen(args[2], "w+");
       if (!fout) {
-        std::cerr << "could not open output .def file: " << args[2] << "\n";
+        std::cerr << "could not open output .def file: " << args[2] << '\n';
         return 1;
       }
       bindexplib deffile;
@@ -824,7 +809,7 @@
         if (cmHasLiteralPrefix(a, "--nm=")) {
           deffile.SetNmPath(a.substr(5));
         } else {
-          std::cerr << "unknown argument: " << a << "\n";
+          std::cerr << "unknown argument: " << a << '\n';
         }
       }
       for (std::string const& file : files) {
@@ -1052,8 +1037,7 @@
     if (args[1] == "touch" && args.size() > 2) {
       for (auto const& arg : cmMakeRange(args).advance(2)) {
         if (!cmSystemTools::Touch(arg, true)) {
-          std::cerr << "cmake -E touch: failed to update \"";
-          std::cerr << arg << "\".\n";
+          std::cerr << "cmake -E touch: failed to update \"" << arg << "\".\n";
           return 1;
         }
       }
@@ -1064,8 +1048,8 @@
     if (args[1] == "touch_nocreate" && args.size() > 2) {
       for (auto const& arg : cmMakeRange(args).advance(2)) {
         if (!cmSystemTools::Touch(arg, false)) {
-          std::cerr << "cmake -E touch_nocreate: failed to update \"";
-          std::cerr << arg << "\".\n";
+          std::cerr << "cmake -E touch_nocreate: failed to update \"" << arg
+                    << "\".\n";
           return 1;
         }
       }
@@ -1115,7 +1099,7 @@
       auto time_finish = std::chrono::steady_clock::now();
 
       std::chrono::duration<double> time_elapsed = time_finish - time_start;
-      std::cout << "Elapsed time (seconds): " << time_elapsed.count() << "\n";
+      std::cout << "Elapsed time (seconds): " << time_elapsed.count() << '\n';
       return ret;
     }
 
@@ -1252,7 +1236,7 @@
         std::string emsg = cmSystemTools::GetLastSystemError();
         std::cerr << "failed to create symbolic link '" << destinationFileName
                   << "' because existing path cannot be removed: " << emsg
-                  << "\n";
+                  << '\n';
         return 1;
       }
       if (!cmSystemTools::CreateSymlink(args[2], destinationFileName)) {
@@ -1269,7 +1253,7 @@
 
       if (!cmSystemTools::FileExists(sourceFileName)) {
         std::cerr << "failed to create hard link because source path '"
-                  << sourceFileName << "' does not exist \n";
+                  << sourceFileName << "' does not exist\n";
         return 1;
       }
 
@@ -1278,7 +1262,7 @@
         std::string emsg = cmSystemTools::GetLastSystemError();
         std::cerr << "failed to create hard link '" << destinationFileName
                   << "' because existing path cannot be removed: " << emsg
-                  << "\n";
+                  << '\n';
         return 1;
       }
 
@@ -1416,7 +1400,7 @@
       if (args.size() == 3) {
         std::cerr << "  Variable " << args[2] << " is not set.";
       }
-      std::cerr << std::endl;
+      std::cerr << '\n';
       return 1;
     }
 
@@ -1535,7 +1519,7 @@
             action = cmSystemTools::TarActionExtract;
           } break;
           default: {
-            std::cerr << "tar: Unknown argument: " << flag << "\n";
+            std::cerr << "tar: Unknown argument: " << flag << '\n';
           }
         }
       }
@@ -1692,17 +1676,17 @@
   for (auto const& filename : cmMakeRange(args).advance(2)) {
     // Cannot compute sum of a directory
     if (cmSystemTools::FileIsDirectory(filename)) {
-      std::cerr << "Error: " << filename << " is a directory" << std::endl;
+      std::cerr << "Error: " << filename << " is a directory\n";
       retval++;
     } else {
       cmCryptoHash hasher(algo);
       std::string value = hasher.HashFile(filename);
       if (value.empty()) {
         // To mimic "md5sum/shasum" behavior in a shell:
-        std::cerr << filename << ": No such file or directory" << std::endl;
+        std::cerr << filename << ": No such file or directory\n";
         retval++;
       } else {
-        std::cout << value << "  " << filename << std::endl;
+        std::cout << value << "  " << filename << '\n';
       }
     }
   }
@@ -1897,8 +1881,7 @@
   // Read command lines from the script.
   cmsys::ifstream fin(args[2].c_str());
   if (!fin) {
-    std::cerr << "Error opening link script \"" << args[2] << "\""
-              << std::endl;
+    std::cerr << "Error opening link script \"" << args[2] << "\"\n";
     return 1;
   }
 
@@ -1929,7 +1912,7 @@
 
     // Report the command if verbose output is enabled.
     if (verbose) {
-      std::cout << command << std::endl;
+      std::cout << command << '\n';
     }
 
     // Run the command and wait for it to exit.
@@ -1971,7 +1954,7 @@
                  "echo Environment Selection: " << name << "\n"
                  "set PATH=" << parser.GetPathDirectories() << "\n"
                  "set INCLUDE=" << parser.GetIncludeDirectories() << "\n"
-                 "set LIB=" << parser.GetLibraryDirectories() << std::endl;
+                 "set LIB=" << parser.GetLibraryDirectories() << '\n';
     /* clang-format on */
     return 0;
   }
@@ -2245,7 +2228,7 @@
 {
   if (verbose) {
     std::cout << comment << ":\n";
-    std::cout << cmJoin(command, " ") << "\n";
+    std::cout << cmJoin(command, " ") << '\n';
   }
   std::string output;
   int retCode = 0;
@@ -2415,7 +2398,7 @@
   std::string absManifestFile =
     cmSystemTools::CollapseFullPath(this->ManifestFile);
   if (this->Verbose) {
-    std::cout << "Create " << this->ManifestFileRC << "\n";
+    std::cout << "Create " << this->ManifestFileRC << '\n';
   }
   {
     cmsys::ofstream fout(this->ManifestFileRC.c_str());
@@ -2423,8 +2406,8 @@
       return -1;
     }
     // Insert a pragma statement to specify utf-8 encoding.
-    fout << "#pragma code_page(65001)\n";
-    fout << this->Type
+    fout << "#pragma code_page(65001)\n"
+         << this->Type
          << " /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ "
             "24 /* RT_MANIFEST */ \""
          << absManifestFile << "\"";
@@ -2434,7 +2417,7 @@
   // generate a manifest file so the resource compiler succeeds.
   if (!cmSystemTools::FileExists(this->ManifestFile)) {
     if (this->Verbose) {
-      std::cout << "Create empty: " << this->ManifestFile << "\n";
+      std::cout << "Create empty: " << this->ManifestFile << '\n';
     }
     if (this->UserManifests.empty()) {
       // generate an empty manifest because there are no user provided
diff --git a/Tests/CPackNSISGenerator/CMakeLists.txt b/Tests/CPackNSISGenerator/CMakeLists.txt
index 5d6320b..cb0b13d 100644
--- a/Tests/CPackNSISGenerator/CMakeLists.txt
+++ b/Tests/CPackNSISGenerator/CMakeLists.txt
@@ -10,6 +10,26 @@
   LIBRARY DESTINATION .
   BUNDLE DESTINATION .)
 
+# Component that is a reserved name on Windows.
+# See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
+install(
+  DIRECTORY .
+  DESTINATION txt
+  COMPONENT CON
+  FILES_MATCHING PATTERN *.txt)
+# Component name that is similar to a reserved name on Windows.
+install(
+  DIRECTORY .
+  DESTINATION txt
+  COMPONENT Console
+  FILES_MATCHING PATTERN *.txt)
+# Component name that is strongly discouraged on Windows.
+install(
+  DIRECTORY .
+  DESTINATION txt
+  COMPONENT EndsWithDot.
+  FILES_MATCHING PATTERN *.txt)
+
 set(CPACK_NSIS_MUI_HEADERIMAGE "${PROJECT_SOURCE_DIR}\\\\header-image.bmp")
 set(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}\\\\header-icon.bmp")
 set(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}\\\\install.ico")
diff --git a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
index 31a2560..3e4d7b4 100644
--- a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
+++ b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
@@ -69,3 +69,24 @@
 else()
   message(FATAL_ERROR "License found in the project")
 endif()
+
+file(STRINGS "${project_file}" line REGEX [[\\_CON\\]])
+string(FIND "${line}" [[\_CON\]] output_index)
+message(STATUS "Found CON component reserved directory name as _CON")
+if("${output_index}" EQUAL "-1")
+  message(FATAL_ERROR "CON component reserved directory name not found as _CON in the project")
+endif()
+
+file(STRINGS "${project_file}" line REGEX [[\\Console\\]])
+string(FIND "${line}" [[\Console\]] output_index)
+message(STATUS "Found Console component directory name as Console")
+if("${output_index}" EQUAL "-1")
+  message(FATAL_ERROR "Console component directory name not found as Console in the project")
+endif()
+
+file(STRINGS "${project_file}" line REGEX [[\\EndsWithDot._\\]])
+string(FIND "${line}" [[\EndsWithDot._\]] output_index)
+message(STATUS "Found EndsWithDot. component directory name as EndsWithDot._")
+if("${output_index}" EQUAL "-1")
+  message(FATAL_ERROR "EndsWithDot. component directory name not found as EndsWithDot._ in the project")
+endif()
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
index f7ede51..5583407 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake
@@ -72,6 +72,7 @@
   run_install_test(linux-unresolved)
   run_install_test(linux-conflict)
   run_install_test(linux-notfile)
+  run_install_test(linux-indirect-dependencies)
   run_cmake(project)
   run_cmake(badargs1)
   run_cmake(badargs2)
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake
index d3d1cd6..012ed58 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-all-check.cmake
@@ -1,4 +1,5 @@
 set(_check
+  [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-build/root-all/lib/conflict/libconflict\.so]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-build/root-all/lib/libtest_rpath\.so]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-build/root-all/lib/libtest_runpath\.so]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-build/root-all/lib/rpath/librpath\.so]]
@@ -19,7 +20,7 @@
 check_contents(deps/udeps2.txt "^${_check}$")
 check_contents(deps/udeps3.txt "^${_check}$")
 set(_check
-  "^libconflict\\.so:[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-build/root-all/lib/conflict/libconflict\\.so;[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-build/root-all/lib/conflict2/libconflict\\.so\n$"
+  "^$"
   )
 check_contents(deps/cdeps1.txt "${_check}")
 check_contents(deps/cdeps2.txt "${_check}")
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-indirect-dependencies-all-stdout.txt b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-indirect-dependencies-all-stdout.txt
new file mode 100644
index 0000000..9f5e07d
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-indirect-dependencies-all-stdout.txt
@@ -0,0 +1 @@
+Resolved dependencies: /
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-indirect-dependencies.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-indirect-dependencies.cmake
new file mode 100644
index 0000000..1d0a913
--- /dev/null
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-indirect-dependencies.cmake
@@ -0,0 +1,83 @@
+enable_language(C)
+cmake_policy(SET CMP0095 NEW)
+
+file(WRITE "${CMAKE_BINARY_DIR}/A.c" "void libA(void) {}\n")
+file(WRITE "${CMAKE_BINARY_DIR}/C.c" "void libC(void) {}\n")
+file(WRITE "${CMAKE_BINARY_DIR}/BUseAC.c" [[
+extern void libA(void);
+extern void libC(void);
+void libB(void)
+{
+    libA();
+    libC();
+}
+]])
+file(WRITE "${CMAKE_BINARY_DIR}/mainABC.c" [[
+extern void libA(void);
+extern void libB(void);
+extern void libC(void);
+
+int main(void)
+{
+    libA();
+    libB();
+    libC();
+    return 0;
+}
+
+]])
+
+set(lib_dirExe "${CMAKE_BINARY_DIR}/Exe")
+set(lib_dirA "${CMAKE_BINARY_DIR}/libA")
+set(lib_dirB "${CMAKE_BINARY_DIR}/libB")
+set(lib_dirC "${CMAKE_BINARY_DIR}/libC")
+file(MAKE_DIRECTORY ${lib_dirExe})
+file(MAKE_DIRECTORY ${lib_dirA})
+file(MAKE_DIRECTORY ${lib_dirB})
+file(MAKE_DIRECTORY ${lib_dirC})
+
+add_library(A SHARED "${CMAKE_BINARY_DIR}/A.c")
+set_property(TARGET A PROPERTY LIBRARY_OUTPUT_DIRECTORY ${lib_dirA})
+
+add_library(C SHARED "${CMAKE_BINARY_DIR}/C.c")
+set_property(TARGET C PROPERTY LIBRARY_OUTPUT_DIRECTORY ${lib_dirC})
+
+# We doesn't need to set A as a dependency of B, because we don't need `RUNPATH` value set for B
+add_library(B SHARED "${CMAKE_BINARY_DIR}/BUseAC.c")
+target_link_libraries(B PRIVATE A C)
+set_property(TARGET B PROPERTY LIBRARY_OUTPUT_DIRECTORY ${lib_dirB})
+
+# We MUST have empty `RUNPATH` in A & B
+set_target_properties(A B C PROPERTIES
+    BUILD_WITH_INSTALL_RPATH 1
+)
+
+# The executable is really workable without `RUNPATH` in B
+add_executable(exe "${CMAKE_BINARY_DIR}/mainABC.c")
+target_link_libraries(exe A B C)
+set_property(TARGET exe PROPERTY RUNTIME_OUTPUT_DIRECTORY ${lib_dirExe})
+
+# We MUST have `RUNPATH` in exe, not `RPATH`
+# Test will pass if we have `RPATH`, because of the inheritance
+target_link_options(exe PRIVATE -Wl,--enable-new-dtags)
+
+install(CODE [[
+    # Work with non-installed binary, because of the RUNPATH values
+    set(exeFile "$<TARGET_FILE:exe>")
+
+    # Check executable is can be successfully finished
+    execute_process(
+        COMMAND "${exeFile}"
+        COMMAND_ERROR_IS_FATAL ANY
+    )
+
+    # Check dependencies resolved
+    file(GET_RUNTIME_DEPENDENCIES
+        RESOLVED_DEPENDENCIES_VAR RESOLVED
+        PRE_INCLUDE_REGEXES "^lib[ABC]\\.so$"
+        PRE_EXCLUDE_REGEXES ".*"
+        EXECUTABLES
+            "${exeFile}"
+    )
+    message(STATUS "Resolved dependencies: ${RESOLVED}")
+]])
diff --git a/Tests/SwiftMixLib/CMakeLists.txt b/Tests/SwiftMixLib/CMakeLists.txt
index d23c6ba..c2cfb8f 100644
--- a/Tests/SwiftMixLib/CMakeLists.txt
+++ b/Tests/SwiftMixLib/CMakeLists.txt
@@ -10,3 +10,15 @@
 
 add_executable(c_main main.c)
 target_link_libraries(c_main PUBLIC SwiftMixedLib)
+
+if(WIN32)
+  # TODO: On macOS and Linux, Swift has mechanism for determining what libraries
+  #       an object, or objects from a static archive, need to link against,
+  #       which is how the Swift driver is able to determine that `c_main`
+  #       needs to link swiftCore. Windows does not have this mechanism.
+  #       Eventually CMake should learn how to do this, explicitly forwarding
+  #       the required library to the link command when linking a static
+  #       archive containing Swift sources into something else, even if the
+  #       linker language is Swift.
+  target_link_libraries(c_main PRIVATE swiftCore)
+endif()