Merge topic 'CheckTypeSize-std-types'

7f786c6a40 Tests: Cover CheckTypeSize with uint8_t and std::uint8_t
371072e9e1 CheckTypeSize: Use C++-style headers to check for std:: types

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !5008
diff --git a/.clang-format b/.clang-format
index 8c015ef..cba23d6 100644
--- a/.clang-format
+++ b/.clang-format
@@ -20,6 +20,8 @@
 SpaceAfterTemplateKeyword: true
 IncludeBlocks: Regroup
 IncludeCategories:
+  - Regex:           '^[<"]cmSTL\.hxx'
+    Priority:        -2
   - Regex:           '^[<"]cmConfigure\.h'
     Priority:        -1
   - Regex:           '^<queue>'
diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml
index c2d28da..be10e24 100644
--- a/.gitlab/artifacts.yml
+++ b/.gitlab/artifacts.yml
@@ -34,10 +34,12 @@
             - build/Tests/CMake*/PseudoMemcheck/purify
             - build/Tests/CMake*/PseudoMemcheck/memcheck_fail
             - build/Tests/CMake*/PseudoMemcheck/BC
+            - build/Tests/CMake*/PseudoMemcheck/cuda-memcheck
             - build/Tests/CMake*/PseudoMemcheck/valgrind.exe
             - build/Tests/CMake*/PseudoMemcheck/purify.exe
             - build/Tests/CMake*/PseudoMemcheck/memcheck_fail.exe
             - build/Tests/CMake*/PseudoMemcheck/BC.exe
+            - build/Tests/CMake*/PseudoMemcheck/cuda-memcheck.exe
             - build/Tests/CMake*/PseudoMemcheck/NoLog
             - build/Tests/CMake*Lib/*LibTests
             - build/Tests/CMake*Lib/*LibTests.exe
diff --git a/Auxiliary/CMakeLists.txt b/Auxiliary/CMakeLists.txt
index a833c79..c0aebef 100644
--- a/Auxiliary/CMakeLists.txt
+++ b/Auxiliary/CMakeLists.txt
@@ -1,4 +1,16 @@
-install(DIRECTORY vim/indent vim/syntax DESTINATION ${CMAKE_XDGDATA_DIR}/vim/vimfiles)
-install(FILES cmake-mode.el DESTINATION ${CMAKE_XDGDATA_DIR}/emacs/site-lisp)
+# Install Vim files to a typical system integration directory.
+# Packagers can set CMake_INSTALL_VIMFILES_DIR to control this.
+if(NOT CMake_INSTALL_VIMFILES_DIR)
+  set(CMake_INSTALL_VIMFILES_DIR ${CMAKE_XDGDATA_DIR}/vim/vimfiles)
+endif()
+install(DIRECTORY vim/indent vim/syntax DESTINATION ${CMake_INSTALL_VIMFILES_DIR})
+
+# Install Emacs files to a typical system integration directory.
+# Packagers can set CMake_INSTALL_EMACS_DIR to control this.
+if(NOT CMake_INSTALL_EMACS_DIR)
+  set(CMake_INSTALL_EMACS_DIR ${CMAKE_XDGDATA_DIR}/emacs/site-lisp)
+endif()
+install(FILES cmake-mode.el DESTINATION ${CMake_INSTALL_EMACS_DIR})
+
 install(FILES cmake.m4 DESTINATION ${CMAKE_XDGDATA_DIR}/aclocal)
 add_subdirectory (bash-completion)
diff --git a/Auxiliary/bash-completion/CMakeLists.txt b/Auxiliary/bash-completion/CMakeLists.txt
index 06d22c2..93b6ffd 100644
--- a/Auxiliary/bash-completion/CMakeLists.txt
+++ b/Auxiliary/bash-completion/CMakeLists.txt
@@ -6,11 +6,16 @@
 # with) as well as a simple installation by a local user into their home
 # directory *if* the prefix is `$HOME/.local` since `.local/share/` is part of
 # the bash-completion search path too.
-# For more complex installations, packagers can set CMAKE_BASH_COMP_DIR to
-# another system location.
+# For more complex installations, packagers can set CMake_INSTALL_BASH_COMP_DIR
+# to another system location.
 
-set(CMAKE_BASH_COMP_DIR_DEFAULT ${CMAKE_XDGDATA_DIR}/bash-completion/completions)
-if (NOT CMAKE_BASH_COMP_DIR)
-  set(CMAKE_BASH_COMP_DIR "${CMAKE_BASH_COMP_DIR_DEFAULT}")
+if(NOT CMake_INSTALL_BASH_COMP_DIR)
+  if(CMAKE_BASH_COMP_DIR)
+    # Honor previous customization option.
+    set(CMake_INSTALL_BASH_COMP_DIR "${CMAKE_BASH_COMP_DIR}")
+  else()
+    # Default.
+    set(CMake_INSTALL_BASH_COMP_DIR ${CMAKE_XDGDATA_DIR}/bash-completion/completions)
+  endif()
 endif()
-install(FILES cmake cpack ctest DESTINATION ${CMAKE_BASH_COMP_DIR})
+install(FILES cmake cpack ctest DESTINATION ${CMake_INSTALL_BASH_COMP_DIR})
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f62c666..2d860d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -108,6 +108,11 @@
   endif()
 endif()
 
+# Inform STL library header wrappers whether to use system versions.
+configure_file(${CMake_SOURCE_DIR}/Utilities/std/cmSTL.hxx.in
+  ${CMake_BINARY_DIR}/Utilities/cmSTL.hxx
+  @ONLY)
+
 # set the internal encoding of CMake to UTF-8
 set(KWSYS_ENCODING_DEFAULT_CODEPAGE CP_UTF8)
 
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index dcc0225..857de78 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -59,7 +59,7 @@
 messages.  Some find-modules provide limited or no support for versioning;
 check the module documentation.
 
-If the ``MODULE`` option is not specfied in the above signature,
+If the ``MODULE`` option is not specified in the above signature,
 CMake first searches for the package using Module mode. Then, if the
 package is not found, it searches again using Config mode. A user
 may set the variable :variable:`CMAKE_FIND_PACKAGE_PREFER_CONFIG` to
diff --git a/Help/command/get_property.rst b/Help/command/get_property.rst
index 123cd45..0602518 100644
--- a/Help/command/get_property.rst
+++ b/Help/command/get_property.rst
@@ -10,7 +10,7 @@
                 DIRECTORY [<dir>]  |
                 TARGET    <target> |
                 SOURCE    <source> |
-                          [TARGET_DIRECTORY <target> | DIRECTORY <dir>] |
+                          [DIRECTORY <dir> | TARGET_DIRECTORY <target>] |
                 INSTALL   <file>   |
                 TEST      <test>   |
                 CACHE     <entry>  |
@@ -31,18 +31,36 @@
   Scope defaults to the current directory but another
   directory (already processed by CMake) may be named by the
   full or relative path ``<dir>``.
+  See also the :command:`get_directory_property` command.
 
 ``TARGET``
   Scope must name one existing target.
+  See also the :command:`get_target_property` command.
 
 ``SOURCE``
-  Scope must name one source file.
+  Scope must name one source file.  By default, the source file's property
+  will be read from the current source directory's scope, but this can be
+  overridden with one of the following sub-options:
+
+  ``DIRECTORY <dir>``
+    The source file property will be read from the ``<dir>`` directory's
+    scope.  CMake must already know about that source directory, either by
+    having added it through a call to :command:`add_subdirectory` or ``<dir>``
+    being the top level source directory.  Relative paths are treated as
+    relative to the current source directory.
+
+  ``TARGET_DIRECTORY <target>``
+    The source file property will be read from the directory scope in which
+    ``<target>`` was created (``<target>`` must therefore already exist).
+
+  See also the :command:`get_source_file_property` command.
 
 ``INSTALL``
   Scope must name one installed file path.
 
 ``TEST``
   Scope must name one existing test.
+  See also the :command:`get_test_property` command.
 
 ``CACHE``
   Scope must name one cache entry.
@@ -50,15 +68,6 @@
 ``VARIABLE``
   Scope is unique and does not accept a name.
 
-In the ``SOURCE`` case, the queried source file scope can be changed by
-specifying one of the additional options: ``DIRECTORY`` or ``TARGET_DIRECTORY``.
-
-``DIRECTORY`` takes a path to a processed directory, and the source file property
-will be read from that directory scope.
-
-``TARGET_DIRECTORY`` takes the name of an existing target. The source file
-property will be read from this target's directory scope.
-
 The required ``PROPERTY`` option is immediately followed by the name of
 the property to get.  If the property is not set an empty value is
 returned, although some properties support inheriting from a parent scope
diff --git a/Help/command/get_source_file_property.rst b/Help/command/get_source_file_property.rst
index 1060251..76ed776 100644
--- a/Help/command/get_source_file_property.rst
+++ b/Help/command/get_source_file_property.rst
@@ -5,24 +5,33 @@
 
 .. code-block:: cmake
 
-  get_source_file_property(VAR file [TARGET_DIRECTORY <target> | DIRECTORY <dir>] property)
+  get_source_file_property(<variable> <file>
+                           [DIRECTORY <dir> | TARGET_DIRECTORY <target>]
+                           <property>)
 
 Gets a property from a source file.  The value of the property is
-stored in the variable ``VAR``.  If the source property is not found, the
-behavior depends on whether it has been defined to be an ``INHERITED`` property
-or not (see :command:`define_property`).  Non-inherited properties will set
-``VAR`` to "NOTFOUND", whereas inherited properties will search the relevant
-parent scope as described for the :command:`define_property` command and
-if still unable to find the property, ``VAR`` will be set to an empty string.
+stored in the specified ``<variable>``.  If the source property is not found,
+the behavior depends on whether it has been defined to be an ``INHERITED``
+property or not (see :command:`define_property`).  Non-inherited properties
+will set ``variable`` to ``NOTFOUND``, whereas inherited properties will search
+the relevant parent scope as described for the :command:`define_property`
+command and if still unable to find the property, ``variable`` will be set to
+an empty string.
 
-The queried source file scope can be changed by specifying one of the
-additional options: ``DIRECTORY`` or ``TARGET_DIRECTORY``.
+By default, the source file's property will be read from the current source
+directory's scope, but this can be overridden with one of the following
+sub-options:
 
-``DIRECTORY`` takes a path to a processed directory, and the source file property
-will be read from that directory scope.
+``DIRECTORY <dir>``
+  The source file property will be read from the ``<dir>`` directory's
+  scope.  CMake must already know about that source directory, either by
+  having added it through a call to :command:`add_subdirectory` or ``<dir>``
+  being the top level source directory.  Relative paths are treated as
+  relative to the current source directory.
 
-``TARGET_DIRECTORY`` takes the name of an existing target. The source file
-property will be read from this target's directory scope.
+``TARGET_DIRECTORY <target>``
+  The source file property will be read from the directory scope in which
+  ``<target>`` was created (``<target>`` must therefore already exist).
 
 Use :command:`set_source_files_properties` to set property values.  Source
 file properties usually control how the file is built. One property that is
diff --git a/Help/command/set_property.rst b/Help/command/set_property.rst
index ccbd635..93c2d9c 100644
--- a/Help/command/set_property.rst
+++ b/Help/command/set_property.rst
@@ -9,13 +9,13 @@
                 DIRECTORY [<dir>]           |
                 TARGET    [<target1> ...]   |
                 SOURCE    [<src1> ...]
-                          [TARGET_DIRECTORY <target1> ...]
-                          [DIRECTORY <dir1> ...] |
+                          [DIRECTORY <dirs> ...] |
+                          [TARGET_DIRECTORY <targets> ...]
                 INSTALL   [<file1> ...]     |
                 TEST      [<test1> ...]     |
                 CACHE     [<entry1> ...]    >
                [APPEND] [APPEND_STRING]
-               PROPERTY <name> [value1 ...])
+               PROPERTY <name> [<value1> ...])
 
 Sets one property on zero or more objects of a scope.
 
@@ -35,17 +35,23 @@
   See also the :command:`set_target_properties` command.
 
 ``SOURCE``
-  Scope may name zero or more source files.  Note that source
-  file properties are by default visible only to targets added in the same
-  directory (``CMakeLists.txt``).
-  The file properties can be made visible in a different directory by specifying
-  one or both of the additional options: ``TARGET_DIRECTORY`` and ``DIRECTORY``.
+  Scope may name zero or more source files.  By default, source file properties
+  are only visible to targets added in the same directory (``CMakeLists.txt``).
+  Visibility can be set in other directory scopes using one or both of the
+  following sub-options:
 
-  ``DIRECTORY`` takes a list of processed directories paths, and sets the file
-  properties in those directory scopes.
+  ``DIRECTORY <dirs>...``
+    The source file property will be set in each of the ``<dirs>``
+    directories' scopes.  CMake must already know about each of these
+    source directories, either by having added them through a call to
+    :command:`add_subdirectory` or it being the top level source directory.
+    Relative paths are treated as relative to the current source directory.
 
-  ``TARGET_DIRECTORY`` takes a list of existing targets. The file
-  properties will be set in these targets' directory scopes.
+  ``TARGET_DIRECTORY <targets>...``
+    The source file property will be set in each of the directory scopes
+    where any of the specified ``<targets>`` were created (the ``<targets>``
+    must therefore already exist).
+
   See also the :command:`set_source_files_properties` command.
 
 ``INSTALL``
diff --git a/Help/command/set_source_files_properties.rst b/Help/command/set_source_files_properties.rst
index 59d5ba3..9558b40 100644
--- a/Help/command/set_source_files_properties.rst
+++ b/Help/command/set_source_files_properties.rst
@@ -5,29 +5,33 @@
 
 .. code-block:: cmake
 
-  set_source_files_properties([file1 [file2 [...]]]
-                              [TARGET_DIRECTORY <target1> ...]
-                              [DIRECTORY <dir1> ...]
-                              PROPERTIES prop1 value1
-                              [prop2 value2 [...]])
+  set_source_files_properties(<files> ...
+                              [DIRECTORY <dirs> ...]
+                              [TARGET_DIRECTORY <targets> ...]
+                              PROPERTIES <prop1> <value1>
+                              [<prop2> <value2>] ...)
 
 Sets properties associated with source files using a key/value paired
 list.
 
-Note that source file properties are by default visible only to
-targets added in the same directory (``CMakeLists.txt``).
+By default, source file properties are only visible to targets added in the
+same directory (``CMakeLists.txt``).  Visibility can be set in other directory
+scopes using one or both of the following options:
 
-The file properties can be made visible in a different directory by specifying
-one or both of the additional options: ``TARGET_DIRECTORY`` and ``DIRECTORY``.
+``DIRECTORY <dirs>...``
+  The source file properties will be set in each of the ``<dirs>``
+  directories' scopes.  CMake must already know about each of these
+  source directories, either by having added them through a call to
+  :command:`add_subdirectory` or it being the top level source directory.
+  Relative paths are treated as relative to the current source directory.
 
-``DIRECTORY`` takes a list of processed directories paths, and sets the file
-properties in those directory scopes.
+``TARGET_DIRECTORY <targets>...``
+  The source file properties will be set in each of the directory scopes
+  where any of the specified ``<targets>`` were created (the ``<targets>``
+  must therefore already exist).
 
-``TARGET_DIRECTORY`` takes a list of existing targets. The file
-properties will be set in these targets' directory scopes.
-
+Use :command:`get_source_file_property` to get property values.
 See also the :command:`set_property(SOURCE)` command.
 
 See :ref:`Source File Properties` for the list of properties known
-to CMake.  Source file properties are visible only to targets added
-in the same directory (``CMakeLists.txt``).
+to CMake.
diff --git a/Help/dev/source.rst b/Help/dev/source.rst
index 0ccb8f4..d93e55c 100644
--- a/Help/dev/source.rst
+++ b/Help/dev/source.rst
@@ -35,6 +35,9 @@
 
 * From ``C++14``:
 
+  * ``<cm/iomanip>``:
+    ``cm::quoted``
+
   * ``<cm/iterator>``:
     ``cm::make_reverse_iterator``, ``cm::cbegin``, ``cm::cend``,
     ``cm::rbegin``, ``cm::rend``, ``cm::crbegin``, ``cm::crend``
@@ -53,6 +56,9 @@
   * ``<cm/algorithm>``:
     ``cm::clamp``
 
+  * ``cm/filesystem>``:
+    ``cm::filesystem::path``
+
   * ``<cm/iterator>``:
     ``cm::size``, ``cm::empty``, ``cm::data``
 
diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst
index e7ea290..e42b4f0 100644
--- a/Help/guide/tutorial/index.rst
+++ b/Help/guide/tutorial/index.rst
@@ -81,8 +81,8 @@
 Next modify ``tutorial.cxx`` to include the configured header file,
 ``TutorialConfig.h``.
 
-Finally, let's print out the version number by updating ``tutorial.cxx`` as
-follows:
+Finally, let's print out the executable name and version number by updating
+``tutorial.cxx`` as follows:
 
 .. literalinclude:: Step2/tutorial.cxx
   :language: c++
@@ -106,7 +106,8 @@
 in CMake is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this
 tutorial, set the :variable:`CMAKE_CXX_STANDARD` variable in the
 ``CMakeLists.txt`` file to 11 and :variable:`CMAKE_CXX_STANDARD_REQUIRED` to
-True:
+True. Make sure to add the ``CMAKE_CXX_STANDARD`` declarations above the call
+to ``add_executable``.
 
 .. literalinclude:: Step2/CMakeLists.txt
   :language: cmake
@@ -120,18 +121,28 @@
 with your chosen build tool.
 
 For example, from the command line we could navigate to the
-``Help/guide/tutorial`` directory of the CMake source code tree and run the
-following commands:
+``Help/guide/tutorial`` directory of the CMake source code tree and create a
+build directory:
 
 .. code-block:: console
 
   mkdir Step1_build
+
+Next, navigate to the build directory and run CMake to configure the project
+and generate a native build system:
+
+.. code-block:: console
+
   cd Step1_build
   cmake ../Step1
+
+Then call that build system to actually compile/link the project:
+
+.. code-block:: console
+
   cmake --build .
 
-Navigate to the directory where Tutorial was built (likely the make directory
-or a Debug or Release build configuration subdirectory) and run these commands:
+Finally, try to use the newly built ``Tutorial`` with these commands:
 
 .. code-block:: console
 
@@ -212,8 +223,9 @@
 classic approach when dealing with many optional components, we will cover
 the modern approach in the next step.
 
-The corresponding changes to the source code are fairly straightforward. First,
-in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we need it:
+The corresponding changes to the source code are fairly straightforward.
+First, in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we
+need it:
 
 .. literalinclude:: Step3/tutorial.cxx
   :language: c++
@@ -242,8 +254,17 @@
 :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
 with your chosen build tool. Then run the built Tutorial executable.
 
-Use the :manual:`ccmake <ccmake(1)>` executable or the :manual:`cmake-gui <cmake-gui(1)>`
-to update the value of ``USE_MYMATH``. Rebuild and run the tutorial again.
+Now let's update the value of ``USE_MYMATH``. The easiest way is to use the
+:manual:`cmake-gui <cmake-gui(1)>` or  :manual:`ccmake <ccmake(1)>` if you're
+in the terminal. Or, alternatively, if you want to change the option from the
+command-line, try:
+
+.. code-block:: console
+
+  cmake ../Step2 -DUSE_MYMATH=OFF
+
+Rebuild and run the tutorial again.
+
 Which function gives better results, sqrt or mysqrt?
 
 Adding Usage Requirements for Library (Step 3)
@@ -320,21 +341,32 @@
 
 That is all that is needed to create a basic local install of the tutorial.
 
-Run the :manual:`cmake  <cmake(1)>` executable or the
+Now run the :manual:`cmake  <cmake(1)>` executable or the
 :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
-with your chosen build tool. Run the install step by using the ``install``
-option of the :manual:`cmake  <cmake(1)>` command (introduced in 3.15, older
-versions of CMake must use ``make install``) from the command line, or build
-the ``INSTALL`` target from an IDE. This will install the appropriate header
-files, libraries, and executables.
+with your chosen build tool.
+
+Then run the install step by using the ``install`` option of the
+:manual:`cmake  <cmake(1)>` command (introduced in 3.15, older versions of
+CMake must use ``make install``) from the command line. For
+multi-configuration tools, don't forget to use the ``--config`` argument to
+specify the configuration. If using an IDE, simply build the ``INSTALL``
+target. This step will install the appropriate header files, libraries, and
+executables. For example:
+
+.. code-block:: console
+
+  cmake --install .
 
 The CMake variable :variable:`CMAKE_INSTALL_PREFIX` is used to determine the
-root of where the files will be installed. If using ``cmake --install`` a
-custom installation directory can be given via the ``--prefix`` argument. For
-multi-configuration tools, use the ``--config`` argument to specify the
-configuration.
+root of where the files will be installed. If using the ``cmake --install``
+command, the installation prefix can be overidden via the ``--prefix``
+argument. For example:
 
-Verify that the installed Tutorial runs.
+.. code-block:: console
+
+  cmake --install . --prefix "/home/myuser/installdir"
+
+Navigate to the install directory and verify that the installed Tutorial runs.
 
 Testing Support
 ---------------
@@ -750,7 +782,7 @@
 :manual:`generator expressions <cmake-generator-expressions(7)>` is to
 conditionally add compiler flags, such as those for language levels or
 warnings. A nice pattern is to associate this information to an ``INTERFACE``
-target allowing this information to propagate. Lets start by constructing an
+target allowing this information to propagate. Let's start by constructing an
 ``INTERFACE`` target and specifying the required C++ standard level of ``11``
 instead of using :variable:`CMAKE_CXX_STANDARD`.
 
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index d5fe34c..544f6ea 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -598,6 +598,13 @@
   .. note::
     Path to where ``<new>`` symbolic link will be created has to exist beforehand.
 
+``create_hardlink <old> <new>``
+  Create a hard link ``<new>`` naming ``<old>``.
+
+  .. note::
+    Path to where ``<new>`` hard link will be created has to exist beforehand.
+    ``<old>`` has to exist beforehand.
+
 ``echo [<string>...]``
   Displays arguments as text.
 
diff --git a/Help/prop_tgt/DEBUG_POSTFIX.rst b/Help/prop_tgt/DEBUG_POSTFIX.rst
index 04e312e..eca7cb0 100644
--- a/Help/prop_tgt/DEBUG_POSTFIX.rst
+++ b/Help/prop_tgt/DEBUG_POSTFIX.rst
@@ -1,7 +1,7 @@
 DEBUG_POSTFIX
 -------------
 
-See target property ``<CONFIG>_POSTFIX``.
+See target property :prop_tgt:`<CONFIG>_POSTFIX`.
 
-This property is a special case of the more-general ``<CONFIG>_POSTFIX``
+This property is a special case of the more-general :prop_tgt:`<CONFIG>_POSTFIX`
 property for the ``DEBUG`` configuration.
diff --git a/Help/prop_tgt/EXCLUDE_FROM_ALL.rst b/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
index c9ece22..f0200f3 100644
--- a/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
+++ b/Help/prop_tgt/EXCLUDE_FROM_ALL.rst
@@ -19,3 +19,10 @@
 in an :command:`install(TARGETS)` command, but the user is responsible for
 ensuring that the target's build artifacts are not missing or outdated when
 an install is performed.
+
+This property may use "generator expressions" with the syntax ``$<...>``. See
+the :manual:`cmake-generator-expressions(7)` manual for available expressions.
+
+Only the "Ninja Multi-Config" generator supports a property value that varies by
+configuration.  For all other generators the value of this property must be the
+same for all configurations.
diff --git a/Help/release/3.18.rst b/Help/release/3.18.rst
index 386b61b..427840e 100644
--- a/Help/release/3.18.rst
+++ b/Help/release/3.18.rst
@@ -318,3 +318,17 @@
 
 * The :manual:`cmake-file-api(7)` "codemodel" version 2 "target" object gained
   a new ``precompileHeaders`` field in the ``compileGroups`` objects.
+
+Updates
+=======
+
+Changes made since CMake 3.18.0 include the following.
+
+3.18.1
+------
+
+* The :generator:`Xcode` generator, when :variable:`CMAKE_OSX_ARCHITECTURES`
+  is not defined, now selects ``$(NATIVE_ARCH_ACTUAL)`` as the default
+  architecture (the Xcode ``ARCHS`` setting).  This is needed for Xcode 12
+  to select the host's architecture, which older versions of Xcode did
+  by default.
diff --git a/Help/release/dev/cmake-E-create_hardlink.rst b/Help/release/dev/cmake-E-create_hardlink.rst
new file mode 100644
index 0000000..66cdc87
--- /dev/null
+++ b/Help/release/dev/cmake-E-create_hardlink.rst
@@ -0,0 +1,5 @@
+cmake-E-create_hardlink
+-----------------------
+
+* The :manual:`cmake(1)` gained a ``-E create_hardlink`` command-line tool
+  that can be used to create hardlinks between files.
diff --git a/Help/release/dev/ctest-cuda-memcheck.rst b/Help/release/dev/ctest-cuda-memcheck.rst
new file mode 100644
index 0000000..f8f861a
--- /dev/null
+++ b/Help/release/dev/ctest-cuda-memcheck.rst
@@ -0,0 +1,8 @@
+CTest
+-----
+
+* :manual:`ctest(1)` gained support for cuda-memcheck as ``CTEST_MEMORYCHECK_COMMAND``.
+  The different tools (memcheck, racecheck, synccheck, initcheck) supplied by
+  cuda-memcheck can be selected by setting the appropriate flags using the
+  ``CTEST_MEMORYCHECK_COMMAND_OPTIONS`` variable.
+  The default flags are `--tool memcheck --leak-check full`.
diff --git a/Help/release/dev/macOS-sdk-latest.rst b/Help/release/dev/macOS-sdk-latest.rst
new file mode 100644
index 0000000..c5ac3a6
--- /dev/null
+++ b/Help/release/dev/macOS-sdk-latest.rst
@@ -0,0 +1,10 @@
+macOS-sdk-latest
+----------------
+
+* Building for macOS will now use the latest SDK available on the system,
+  unless the user has explicitly chosen a SDK using :variable:`CMAKE_OSX_SYSROOT`.
+
+  The deployment target or system macOS version will not affect
+  the choice of SDK.
+
+* macOS SDKs older than 10.5 are no longer supported.
diff --git a/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst b/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
index 34512b4..07342b5 100644
--- a/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
+++ b/Help/variable/CMAKE_CUDA_HOST_COMPILER.rst
@@ -3,8 +3,23 @@
 
 .. versionadded:: 3.10
 
-Executable to use when compiling host code when compiling ``CUDA`` language
-files. Maps to the ``nvcc -ccbin`` option.  Will only be used by CMake on the first
-configuration to determine a valid host compiler for ``CUDA``. After a valid
-host compiler has been found, this value is read-only.  This variable takes
-priority over the :envvar:`CUDAHOSTCXX` environment variable.
+When :variable:`CMAKE_CUDA_COMPILER <CMAKE_<LANG>_COMPILER>` is set to
+NVIDIA ``nvcc``, ``CMAKE_CUDA_HOST_COMPILER`` selects the compiler
+executable to use when compiling host code for ``CUDA`` language files.
+This maps to the ``nvcc -ccbin`` option.
+
+The ``CMAKE_CUDA_HOST_COMPILER`` variable may be set explicitly before CUDA is
+first enabled by a :command:`project` or :command:`enable_language` command.
+This can be done via ``-DCMAKE_CUDA_HOST_COMPILER=...`` on the command line
+or in a :ref:`toolchain file <Cross Compiling Toolchain>`.  Or, one may set
+the :envvar:`CUDAHOSTCXX` environment variable to provide a default value.
+
+Once the CUDA language is enabled, the ``CMAKE_CUDA_HOST_COMPILER`` variable
+is read-only and changes to it are undefined behavior.
+
+.. note::
+
+  Since ``CMAKE_CUDA_HOST_COMPILER`` is meaningful only when the
+  ``CMAKE_CUDA_COMPILER`` is ``nvcc``, it does not make sense to
+  set ``CMAKE_CUDA_HOST_COMPILER`` explicitly without also setting
+  ``CMAKE_CUDA_COMPILER`` explicitly to be sure it is ``nvcc``.
diff --git a/Modules/CMakeDetermineCUDACompiler.cmake b/Modules/CMakeDetermineCUDACompiler.cmake
index 692ce20..fa497cd 100644
--- a/Modules/CMakeDetermineCUDACompiler.cmake
+++ b/Modules/CMakeDetermineCUDACompiler.cmake
@@ -188,7 +188,7 @@
   if(CMAKE_CUDA_COMPILER_ID STREQUAL "NVIDIA")
     set(nvcc_test_flags "--keep --keep-dir tmp")
     if(CMAKE_CUDA_HOST_COMPILER)
-      string(APPEND nvcc_test_flags " -ccbin=${CMAKE_CUDA_HOST_COMPILER}")
+      string(APPEND nvcc_test_flags " -ccbin=\"${CMAKE_CUDA_HOST_COMPILER}\"")
     endif()
   elseif(CMAKE_CUDA_COMPILER_ID STREQUAL "Clang")
     if(WIN32)
@@ -456,7 +456,7 @@
       "Parsed CUDA nvcc implicit link information from above output:\n${_nvcc_log}\n${log}\n\n")
   else()
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
-      "Failed to parsed CUDA nvcc implicit link information:\n${_nvcc_log}\n\n")
+      "Failed to parse CUDA nvcc implicit link information:\n${_nvcc_log}\n\n")
     message(FATAL_ERROR "Failed to extract nvcc implicit link line.")
   endif()
 endif()
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index ebfd5a4..8200200 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -490,6 +490,12 @@
         set(id_clang_cxx_library "CLANG_CXX_LIBRARY = \"${CMAKE_MATCH_3}\";")
       endif()
     endif()
+    if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT MATCHES "^$|[Mm][Aa][Cc][Oo][Ss]")
+      # When targeting macOS, use only the host architecture.
+      set(id_archs [[ARCHS = "$(NATIVE_ARCH_ACTUAL)";]])
+    else()
+      set(id_archs "")
+    endif()
     configure_file(${CMAKE_ROOT}/Modules/CompilerId/Xcode-3.pbxproj.in
       ${id_dir}/CompilerId${lang}.xcodeproj/project.pbxproj @ONLY)
     unset(_ENV_MACOSX_DEPLOYMENT_TARGET)
diff --git a/Modules/CMakePlatformId.h.in b/Modules/CMakePlatformId.h.in
index 40668a3..0b81c88 100644
--- a/Modules/CMakePlatformId.h.in
+++ b/Modules/CMakePlatformId.h.in
@@ -206,6 +206,24 @@
 # else /* unknown architecture */
 #  define ARCHITECTURE_ID ""
 # endif
+
+#elif defined(__TI_COMPILER_VERSION__)
+# if defined(__TI_ARM__)
+#  define ARCHITECTURE_ID "ARM"
+
+# elif defined(__MSP430__)
+#  define ARCHITECTURE_ID "MSP430"
+
+# elif defined(__TMS320C28XX__)
+#  define ARCHITECTURE_ID "TMS320C28x"
+
+# elif defined(__TMS320C6X__) || defined(_TMS320C6X)
+#  define ARCHITECTURE_ID "TMS320C6x"
+
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+
 #else
 #  define ARCHITECTURE_ID
 #endif
@@ -283,4 +301,3 @@
    array rather than assigning a pointer to a static array.  */
 char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]";
 char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]";
-
diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake
index d67d8d3..44387d4 100644
--- a/Modules/CheckLanguage.cmake
+++ b/Modules/CheckLanguage.cmake
@@ -20,7 +20,7 @@
 as the compiler that was found, or ``NOTFOUND`` if the language cannot be
 enabled. For CUDA which can have an explicit host compiler, the cache
 :variable:`CMAKE_CUDA_HOST_COMPILER` variable will be set if it was required
-for compilation.
+for compilation (and cleared if it was not).
 
 Example:
 
diff --git a/Modules/Compiler/TI-ASM.cmake b/Modules/Compiler/TI-ASM.cmake
index a566d70..01965d2 100644
--- a/Modules/Compiler/TI-ASM.cmake
+++ b/Modules/Compiler/TI-ASM.cmake
@@ -1,8 +1,4 @@
-set(CMAKE_LIBRARY_PATH_FLAG "--search_path=")
-set(CMAKE_LINK_LIBRARY_FLAG "--library=")
-set(CMAKE_INCLUDE_FLAG_ASM "--include_path=")
-
-set(CMAKE_ASM_COMPILE_OBJECT  "<CMAKE_ASM_COMPILER> --compile_only --asm_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<OBJECT>")
-set(CMAKE_ASM_LINK_EXECUTABLE "<CMAKE_ASM_COMPILER> <OBJECTS> --run_linker --output_file=<TARGET> <CMAKE_ASM_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>")
+include(Compiler/TI)
+__compiler_ti(ASM)
 
 set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS asm;s;abs)
diff --git a/Modules/Compiler/TI-C.cmake b/Modules/Compiler/TI-C.cmake
index b060ee9..8ea01b5 100644
--- a/Modules/Compiler/TI-C.cmake
+++ b/Modules/Compiler/TI-C.cmake
@@ -1,22 +1,8 @@
-set(CMAKE_LIBRARY_PATH_FLAG "--search_path=")
-set(CMAKE_LINK_LIBRARY_FLAG "--library=")
-set(CMAKE_INCLUDE_FLAG_C "--include_path=")
+include(Compiler/TI)
+__compiler_ti(C)
 
 set(CMAKE_C90_STANDARD_COMPILE_OPTION "--c89")
 set(CMAKE_C90_EXTENSION_COMPILE_OPTION "--c89 --relaxed_ansi")
 
 set(CMAKE_C99_STANDARD_COMPILE_OPTION "--c99")
 set(CMAKE_C99_EXTENSION_COMPILE_OPTION "--c99 --relaxed_ansi")
-
-set(CMAKE_DEPFILE_FLAGS_C "--preproc_with_compile --preproc_dependency=<DEPFILE>")
-
-set(CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> --compile_only --skip_assembler --c_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<ASSEMBLY_SOURCE>")
-set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> --preproc_only --c_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<PREPROCESSED_SOURCE>")
-
-set(CMAKE_C_COMPILE_OBJECT  "<CMAKE_C_COMPILER> --compile_only --c_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<OBJECT>")
-set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qr <TARGET> <OBJECTS>")
-set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> qa <TARGET> <OBJECTS>")
-set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> --run_linker --output_file=<TARGET> --map_file=<TARGET_NAME>.map <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES>")
-set(CMAKE_ASM_RESPONSE_FILE_FLAG "--cmd_file=")
-set(CMAKE_C_RESPONSE_FILE_FLAG "--cmd_file=")
-set(CMAKE_C_RESPONSE_FILE_LINK_FLAG " ")
diff --git a/Modules/Compiler/TI-CXX.cmake b/Modules/Compiler/TI-CXX.cmake
index 7836543..c08d9a1 100644
--- a/Modules/Compiler/TI-CXX.cmake
+++ b/Modules/Compiler/TI-CXX.cmake
@@ -1,15 +1,2 @@
-set(CMAKE_LIBRARY_PATH_FLAG "--search_path=")
-set(CMAKE_LINK_LIBRARY_FLAG "--library=")
-set(CMAKE_INCLUDE_FLAG_CXX "--include_path=")
-
-set(CMAKE_DEPFILE_FLAGS_CXX "--preproc_with_compile --preproc_dependency=<DEPFILE>")
-
-set(CMAKE_CXX_CREATE_ASSEMBLY_SOURCE "<CMAKE_CXX_COMPILER> --compile_only --skip_assembler --cpp_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<ASSEMBLY_SOURCE>")
-set(CMAKE_CXX_CREATE_PREPROCESSED_SOURCE "<CMAKE_CXX_COMPILER> --preproc_only --cpp_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<PREPROCESSED_SOURCE>")
-
-set(CMAKE_CXX_COMPILE_OBJECT  "<CMAKE_CXX_COMPILER> --compile_only --cpp_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<OBJECT>")
-set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qr <TARGET> <OBJECTS>")
-set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> qa <TARGET> <OBJECTS>")
-set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> --run_linker --output_file=<TARGET> --map_file=<TARGET_NAME>.map <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES>")
-set(CMAKE_CXX_RESPONSE_FILE_FLAG "--cmd_file=")
-set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG " ")
+include(Compiler/TI)
+__compiler_ti(CXX)
diff --git a/Modules/Compiler/TI.cmake b/Modules/Compiler/TI.cmake
new file mode 100644
index 0000000..9f2e813
--- /dev/null
+++ b/Modules/Compiler/TI.cmake
@@ -0,0 +1,40 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This module is shared by multiple languages; use include blocker.
+if(__COMPILER_TI)
+  return()
+endif()
+set(__COMPILER_TI 1)
+
+macro(__compiler_ti lang)
+  string(TOLOWER ${lang} prefix)
+  if("x${lang}" STREQUAL "xCXX")
+    set(prefix "cpp")
+  endif()
+
+  set(CMAKE_${lang}_RESPONSE_FILE_FLAG "--cmd_file=")
+
+  set(CMAKE_INCLUDE_FLAG_${lang} "--include_path=")
+  set(CMAKE_DEPFILE_FLAGS_${lang} "--preproc_with_compile --preproc_dependency=<DEPFILE>")
+
+  set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> --preproc_only --${prefix}_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<PREPROCESSED_SOURCE>")
+  set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE     "<CMAKE_${lang}_COMPILER> --compile_only --skip_assembler --${prefix}_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<ASSEMBLY_SOURCE>")
+
+  set(CMAKE_${lang}_COMPILE_OBJECT  "<CMAKE_${lang}_COMPILER> --compile_only --${prefix}_file=<SOURCE> <DEFINES> <INCLUDES> <FLAGS> --output_file=<OBJECT>")
+
+  set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qr <TARGET> <OBJECTS>")
+  set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> qa <TARGET> <OBJECTS>")
+  set(CMAKE_${lang}_ARCHIVE_FINISH "")
+
+  # After the --run_linker flag a response file is not possible
+  set(CMAKE_${lang}_RESPONSE_FILE_LINK_FLAG "")
+  set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
+  set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 0)
+
+  set(CMAKE_${lang}_LINK_EXECUTABLE "<CMAKE_${lang}_COMPILER> <FLAGS> --run_linker --output_file=<TARGET> --map_file=<TARGET_NAME>.map <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES>")
+endmacro()
+
+set(CMAKE_LIBRARY_PATH_FLAG "--search_path=")
+set(CMAKE_LINK_LIBRARY_FLAG "--library=")
diff --git a/Modules/CompilerId/Xcode-3.pbxproj.in b/Modules/CompilerId/Xcode-3.pbxproj.in
index 672044e..6fe17e5 100644
--- a/Modules/CompilerId/Xcode-3.pbxproj.in
+++ b/Modules/CompilerId/Xcode-3.pbxproj.in
@@ -84,6 +84,7 @@
 				CODE_SIGNING_REQUIRED = NO;
 				CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
 				SYMROOT = .;
+				@id_archs@
 				@id_toolset@
 				@id_lang_version@
 				@id_clang_cxx_library@
diff --git a/Modules/FindX11.cmake b/Modules/FindX11.cmake
index aa83575..958a22e 100644
--- a/Modules/FindX11.cmake
+++ b/Modules/FindX11.cmake
@@ -59,6 +59,7 @@
   X11_XShm_INCLUDE_PATH,         (in X11_Xext_LIB),  X11_XShm_FOUND
   X11_Xshape_INCLUDE_PATH,       (in X11_Xext_LIB),  X11_Xshape_FOUND
   X11_XSync_INCLUDE_PATH,        (in X11_Xext_LIB),  X11_XSync_FOUND
+  X11_Xaw_INCLUDE_PATH,          X11_Xaw_LIB         X11_Xaw_FOUND         X11::Xaw
 #]=======================================================================]
 
 if (UNIX)
@@ -100,6 +101,7 @@
   find_path(X11_Xaccessrules_INCLUDE_PATH X11/extensions/XKBrules.h  ${X11_INC_SEARCH_PATH})
   find_path(X11_Xaccessstr_INCLUDE_PATH X11/extensions/XKBstr.h      ${X11_INC_SEARCH_PATH})
   find_path(X11_Xau_INCLUDE_PATH X11/Xauth.h                         ${X11_INC_SEARCH_PATH})
+  find_path(X11_Xaw_INCLUDE_PATH X11/Xaw/Intrinsic.h                 ${X11_INC_SEARCH_PATH})
   find_path(X11_xcb_INCLUDE_PATH xcb/xcb.h                           ${X11_INC_SEARCH_PATH})
   find_path(X11_X11_xcb_INCLUDE_PATH X11/Xlib-xcb.h                  ${X11_INC_SEARCH_PATH})
   find_path(X11_xcb_icccm_INCLUDE_PATH xcb/xcb_icccm.h               ${X11_INC_SEARCH_PATH})
@@ -134,6 +136,8 @@
   find_path(X11_Xv_INCLUDE_PATH X11/extensions/Xvlib.h               ${X11_INC_SEARCH_PATH})
   find_path(X11_XSync_INCLUDE_PATH X11/extensions/sync.h             ${X11_INC_SEARCH_PATH})
 
+
+
   # Backwards compatibility.
   set(X11_Xinput_INCLUDE_PATH "${X11_Xi_INCLUDE_PATH}")
   set(X11_xf86misc_INCLUDE_PATH "${X11_Xxf86misc_INCLUDE_PATH}")
@@ -148,6 +152,7 @@
   find_library(X11_ICE_LIB ICE               ${X11_LIB_SEARCH_PATH})
   find_library(X11_SM_LIB SM                 ${X11_LIB_SEARCH_PATH})
   find_library(X11_Xau_LIB Xau               ${X11_LIB_SEARCH_PATH})
+  find_library(X11_Xaw_LIB Xaw               ${X11_LIB_SEARCH_PATH})
   find_library(X11_xcb_LIB xcb               ${X11_LIB_SEARCH_PATH})
   find_library(X11_X11_xcb_LIB X11-xcb       ${X11_LIB_SEARCH_PATH})
   find_library(X11_xcb_icccm_LIB xcb-icccm   ${X11_LIB_SEARCH_PATH})
@@ -392,6 +397,10 @@
      set(X11_SM_FOUND TRUE)
   endif()
 
+  if(X11_Xaw_LIB AND X11_Xaw_INCLUDE_PATH)
+      set(X11_Xaw_FOUND TRUE)
+  endif()
+
   # Most of the X11 headers will be in the same directories, avoid
   # creating a huge list of duplicates.
   if (X11_INCLUDE_DIR)
@@ -519,6 +528,14 @@
       INTERFACE_INCLUDE_DIRECTORIES "${X11_Xau_INCLUDE_PATH}")
   endif ()
 
+  if (X11_Xaw_FOUND AND NOT TARGET X11::Xaw)
+    add_library(X11::Xaw UNKNOWN IMPORTED)
+    set_target_properties(X11::Xaw PROPERTIES
+      IMPORTED_LOCATION "${X11_Xaw_LIB}"
+      INTERFACE_INCLUDE_DIRECTORIES "${X11_Xaw_INCLUDE_PATH}"
+      INTERFACE_LINK_LIBRARIES "X11::Xext;X11::Xmu;X11::Xt;X11::Xpm;X11::X11")
+  endif ()
+
   if (X11_xcb_FOUND AND NOT TARGET X11::xcb)
     add_library(X11::xcb UNKNOWN IMPORTED)
     set_target_properties(X11::xcb PROPERTIES
@@ -817,6 +834,8 @@
     X11_SM_LIB
     X11_SM_INCLUDE_PATH
     X11_XSync_INCLUDE_PATH
+    X11_Xaw_LIB
+    X11_Xaw_INCLUDE_PATH
   )
   set(CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_SAVE})
   set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE})
diff --git a/Modules/Platform/Darwin-Initialize.cmake b/Modules/Platform/Darwin-Initialize.cmake
index aa0e554..d087412 100644
--- a/Modules/Platform/Darwin-Initialize.cmake
+++ b/Modules/Platform/Darwin-Initialize.cmake
@@ -72,35 +72,26 @@
   endif()
 
   if(_CMAKE_OSX_SDKS_DIR)
-    # Select SDK for current OSX version accounting for the known
-    # specially named SDKs.
-    set(_CMAKE_OSX_SDKS_VER_SUFFIX_10.4 "u")
-    set(_CMAKE_OSX_SDKS_VER_SUFFIX_10.3 ".9")
-
-    # find the latest SDK
+    # Find the latest SDK as recommended by Apple (Technical Q&A QA1806)
     set(_CMAKE_OSX_LATEST_SDK_VERSION "0.0")
     file(GLOB _CMAKE_OSX_SDKS RELATIVE "${_CMAKE_OSX_SDKS_DIR}" "${_CMAKE_OSX_SDKS_DIR}/MacOSX*.sdk")
     foreach(_SDK ${_CMAKE_OSX_SDKS})
-      if(_SDK MATCHES "MacOSX([0-9]+\\.[0-9]+)[^/]*\\.sdk" AND CMAKE_MATCH_1 VERSION_GREATER ${_CMAKE_OSX_LATEST_SDK_VERSION})
+      if(IS_DIRECTORY "${_CMAKE_OSX_SDKS_DIR}/${_SDK}"
+         AND _SDK MATCHES "MacOSX([0-9]+\\.[0-9]+)[^/]*\\.sdk"
+         AND CMAKE_MATCH_1 VERSION_GREATER ${_CMAKE_OSX_LATEST_SDK_VERSION})
         set(_CMAKE_OSX_LATEST_SDK_VERSION "${CMAKE_MATCH_1}")
       endif()
     endforeach()
 
-    # pick an SDK that works
-    set(_CMAKE_OSX_SYSROOT_DEFAULT)
-    foreach(_ver ${CMAKE_OSX_DEPLOYMENT_TARGET}
-                 ${_CURRENT_OSX_VERSION}
-                 ${_CMAKE_OSX_LATEST_SDK_VERSION})
-      set(_CMAKE_OSX_DEPLOYMENT_TARGET ${_ver})
-      set(_CMAKE_OSX_SDKS_VER ${_CMAKE_OSX_DEPLOYMENT_TARGET}${_CMAKE_OSX_SDKS_VER_SUFFIX_${_CMAKE_OSX_DEPLOYMENT_TARGET}})
-      set(_CMAKE_OSX_SYSROOT_CHECK "${_CMAKE_OSX_SDKS_DIR}/MacOSX${_CMAKE_OSX_SDKS_VER}.sdk")
-      if(IS_DIRECTORY "${_CMAKE_OSX_SYSROOT_CHECK}")
-        set(_CMAKE_OSX_SYSROOT_DEFAULT "${_CMAKE_OSX_SYSROOT_CHECK}")
-        break()
-      endif()
-    endforeach()
+    if(NOT _CMAKE_OSX_LATEST_SDK_VERSION STREQUAL "0.0")
+      set(_CMAKE_OSX_SYSROOT_DEFAULT "${_CMAKE_OSX_SDKS_DIR}/MacOSX${_CMAKE_OSX_LATEST_SDK_VERSION}.sdk")
+    else()
+      message(WARNING "Could not find any valid SDKs in ${_CMAKE_OSX_SDKS_DIR}")
+    endif()
 
-    if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_OSX_DEPLOYMENT_TARGET AND _CURRENT_OSX_VERSION VERSION_LESS _CMAKE_OSX_DEPLOYMENT_TARGET)
+    if(NOT CMAKE_CROSSCOMPILING AND NOT CMAKE_OSX_DEPLOYMENT_TARGET
+       AND (_CURRENT_OSX_VERSION VERSION_LESS _CMAKE_OSX_LATEST_SDK_VERSION
+            OR _CMAKE_OSX_LATEST_SDK_VERSION STREQUAL "0.0"))
       set(CMAKE_OSX_DEPLOYMENT_TARGET ${_CURRENT_OSX_VERSION} CACHE STRING
         "Minimum OS X version to target for deployment (at runtime); newer APIs weak linked. Set to empty string for default value." FORCE)
     endif()
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index b1df0e7..871da4f 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 18)
-set(CMake_VERSION_PATCH 20200712)
+set(CMake_VERSION_PATCH 20200723)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx
index 85b8ab1..d2772a7 100644
--- a/Source/CTest/cmCTestMemCheckHandler.cxx
+++ b/Source/CTest/cmCTestMemCheckHandler.cxx
@@ -326,6 +326,9 @@
     case cmCTestMemCheckHandler::BOUNDS_CHECKER:
       xml.Attribute("Checker", "BoundsChecker");
       break;
+    case cmCTestMemCheckHandler::CUDA_MEMCHECK:
+      xml.Attribute("Checker", "CudaMemcheck");
+      break;
     case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
       xml.Attribute("Checker", "AddressSanitizer");
       break;
@@ -465,6 +468,8 @@
       this->MemoryTesterStyle = cmCTestMemCheckHandler::PURIFY;
     } else if (testerName.find("BC") != std::string::npos) {
       this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+    } else if (testerName.find("cuda-memcheck") != std::string::npos) {
+      this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_MEMCHECK;
     } else {
       this->MemoryTesterStyle = cmCTestMemCheckHandler::UNKNOWN;
     }
@@ -485,6 +490,11 @@
     this->MemoryTester =
       this->CTest->GetCTestConfiguration("BoundsCheckerCommand");
     this->MemoryTesterStyle = cmCTestMemCheckHandler::BOUNDS_CHECKER;
+  } else if (cmSystemTools::FileExists(
+               this->CTest->GetCTestConfiguration("CudaMemcheckCommand"))) {
+    this->MemoryTester =
+      this->CTest->GetCTestConfiguration("CudaMemcheckCommand");
+    this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_MEMCHECK;
   }
   if (this->CTest->GetCTestConfiguration("MemoryCheckType") ==
       "AddressSanitizer") {
@@ -528,6 +538,8 @@
       this->MemoryTesterStyle = cmCTestMemCheckHandler::VALGRIND;
     } else if (checkType == "DrMemory") {
       this->MemoryTesterStyle = cmCTestMemCheckHandler::DRMEMORY;
+    } else if (checkType == "CudaMemcheck") {
+      this->MemoryTesterStyle = cmCTestMemCheckHandler::CUDA_MEMCHECK;
     }
   }
   if (this->MemoryTester.empty()) {
@@ -553,6 +565,10 @@
                 .empty()) {
     memoryTesterOptions =
       this->CTest->GetCTestConfiguration("DrMemoryCommandOptions");
+  } else if (!this->CTest->GetCTestConfiguration("CudaMemcheckCommandOptions")
+                .empty()) {
+    memoryTesterOptions =
+      this->CTest->GetCTestConfiguration("CudaMemcheckCommandOptions");
   }
   this->MemoryTesterOptions =
     cmSystemTools::ParseArguments(memoryTesterOptions);
@@ -686,6 +702,18 @@
       this->MemoryTesterOptions.emplace_back("/M");
       break;
     }
+    case cmCTestMemCheckHandler::CUDA_MEMCHECK: {
+      // cuda-memcheck separates flags from arguments by spaces
+      if (this->MemoryTesterOptions.empty()) {
+        this->MemoryTesterOptions.emplace_back("--tool");
+        this->MemoryTesterOptions.emplace_back("memcheck");
+        this->MemoryTesterOptions.emplace_back("--leak-check");
+        this->MemoryTesterOptions.emplace_back("full");
+      }
+      this->MemoryTesterDynamicOptions.emplace_back("--log-file");
+      this->MemoryTesterDynamicOptions.push_back(this->MemoryTesterOutputFile);
+      break;
+    }
     // these are almost the same but the env var used is different
     case cmCTestMemCheckHandler::ADDRESS_SANITIZER:
     case cmCTestMemCheckHandler::LEAK_SANITIZER:
@@ -771,6 +799,8 @@
       return this->ProcessMemCheckSanitizerOutput(str, log, results);
     case cmCTestMemCheckHandler::BOUNDS_CHECKER:
       return this->ProcessMemCheckBoundsCheckerOutput(str, log, results);
+    case cmCTestMemCheckHandler::CUDA_MEMCHECK:
+      return this->ProcessMemCheckCudaOutput(str, log, results);
     default:
       log.append("\nMemory checking style used was: ");
       log.append("None that I know");
@@ -1103,6 +1133,118 @@
   return defects == 0;
 }
 
+bool cmCTestMemCheckHandler::ProcessMemCheckCudaOutput(
+  const std::string& str, std::string& log, std::vector<int>& results)
+{
+  std::vector<std::string> lines;
+  cmsys::SystemTools::Split(str, lines);
+  bool unlimitedOutput = false;
+  if (str.find("CTEST_FULL_OUTPUT") != std::string::npos ||
+      this->CustomMaximumFailedTestOutputSize == 0) {
+    unlimitedOutput = true;
+  }
+
+  std::string::size_type cc;
+
+  std::ostringstream ostr;
+  log.clear();
+
+  int defects = 0;
+
+  cmsys::RegularExpression memcheckLine("^========");
+
+  cmsys::RegularExpression leakExpr("== Leaked [0-9,]+ bytes at");
+
+  // list of matchers for output messages that contain variable content
+  // (addresses, sizes, ...) or can be shortened in general. the first match is
+  // used as a error name.
+  std::vector<cmsys::RegularExpression> matchers{
+    // API errors
+    "== Malloc/Free error encountered: (.*)",
+    "== Program hit error ([^ ]*).* on CUDA API call to",
+    "== Program hit ([^ ]*).* on CUDA API call to",
+    // memcheck
+    "== (Invalid .*) of size [0-9,]+",
+    // racecheck
+    "== .* (Potential .* hazard detected)", "== .* (Race reported)",
+    // synccheck
+    "== (Barrier error)",
+    // initcheck
+    "== (Uninitialized .* memory read)", "== (Unused memory)",
+    // generic error: ignore ERROR SUMMARY, CUDA-MEMCHECK and others
+    "== ([A-Z][a-z].*)"
+  };
+
+  std::vector<std::string::size_type> nonMemcheckOutput;
+  auto sttime = std::chrono::steady_clock::now();
+  cmCTestOptionalLog(this->CTest, DEBUG,
+                     "Start test: " << lines.size() << std::endl, this->Quiet);
+  std::string::size_type totalOutputSize = 0;
+  for (cc = 0; cc < lines.size(); cc++) {
+    cmCTestOptionalLog(this->CTest, DEBUG,
+                       "test line " << lines[cc] << std::endl, this->Quiet);
+
+    if (memcheckLine.find(lines[cc])) {
+      cmCTestOptionalLog(this->CTest, DEBUG,
+                         "cuda-memcheck line " << lines[cc] << std::endl,
+                         this->Quiet);
+      int failure = -1;
+      auto& line = lines[cc];
+      if (leakExpr.find(line)) {
+        failure = static_cast<int>(this->FindOrAddWarning("Memory leak"));
+      } else {
+        for (auto& matcher : matchers) {
+          if (matcher.find(line)) {
+            failure =
+              static_cast<int>(this->FindOrAddWarning(matcher.match(1)));
+            break;
+          }
+        }
+      }
+
+      if (failure >= 0) {
+        ostr << "<b>" << this->ResultStrings[failure] << "</b> ";
+        if (results.empty() || unsigned(failure) > results.size() - 1) {
+          results.push_back(1);
+        } else {
+          results[failure]++;
+        }
+        defects++;
+      }
+      totalOutputSize += lines[cc].size();
+      ostr << lines[cc] << std::endl;
+    } else {
+      nonMemcheckOutput.push_back(cc);
+    }
+  }
+  // Now put all all the non cuda-memcheck output into the test output
+  // This should be last in case it gets truncated by the output
+  // limiting code
+  for (std::string::size_type i : nonMemcheckOutput) {
+    totalOutputSize += lines[i].size();
+    ostr << lines[i] << std::endl;
+    if (!unlimitedOutput &&
+        totalOutputSize >
+          static_cast<size_t>(this->CustomMaximumFailedTestOutputSize)) {
+      ostr << "....\n";
+      ostr << "Test Output for this test has been truncated see testing"
+              " machine logs for full output,\n";
+      ostr << "or put CTEST_FULL_OUTPUT in the output of "
+              "this test program.\n";
+      break; // stop the copy of output if we are full
+    }
+  }
+  cmCTestOptionalLog(this->CTest, DEBUG,
+                     "End test (elapsed: "
+                       << cmDurationTo<unsigned int>(
+                            std::chrono::steady_clock::now() - sttime)
+                       << "s)" << std::endl,
+                     this->Quiet);
+  log = ostr.str();
+  this->DefectCount += defects;
+  return defects == 0;
+}
+
 // PostProcessTest memcheck results
 void cmCTestMemCheckHandler::PostProcessTest(cmCTestTestResult& res, int test)
 {
diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h
index 52667f8..63ab573 100644
--- a/Source/CTest/cmCTestMemCheckHandler.h
+++ b/Source/CTest/cmCTestMemCheckHandler.h
@@ -46,6 +46,7 @@
     DRMEMORY,
     BOUNDS_CHECKER,
     // checkers after here do not use the standard error list
+    CUDA_MEMCHECK,
     ADDRESS_SANITIZER,
     LEAK_SANITIZER,
     THREAD_SANITIZER,
@@ -137,6 +138,8 @@
                                      std::vector<int>& results);
   bool ProcessMemCheckPurifyOutput(const std::string& str, std::string& log,
                                    std::vector<int>& results);
+  bool ProcessMemCheckCudaOutput(const std::string& str, std::string& log,
+                                 std::vector<int>& results);
   bool ProcessMemCheckSanitizerOutput(const std::string& str, std::string& log,
                                       std::vector<int>& results);
   bool ProcessMemCheckBoundsCheckerOutput(const std::string& str,
diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake
index 50ccc7c..e726fc7 100644
--- a/Source/Checks/cm_cxx_features.cmake
+++ b/Source/Checks/cm_cxx_features.cmake
@@ -63,3 +63,8 @@
   set(CMake_HAVE_CXX_UNIQUE_PTR 1)
 endif()
 cm_check_cxx_feature(unique_ptr)
+if (NOT CMAKE_CXX_STANDARD LESS "17")
+  cm_check_cxx_feature(filesystem)
+else()
+  set(CMake_HAVE_CXX_FILESYSTEM FALSE)
+endif()
diff --git a/Source/Checks/cm_cxx_filesystem.cxx b/Source/Checks/cm_cxx_filesystem.cxx
new file mode 100644
index 0000000..e508d1c
--- /dev/null
+++ b/Source/Checks/cm_cxx_filesystem.cxx
@@ -0,0 +1,10 @@
+
+#include <filesystem>
+
+int main()
+{
+  std::filesystem::path p1("/a/b/c");
+  std::filesystem::path p2("/a/b/c");
+
+  return p1 == p2 ? 0 : 1;
+}
diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx
index 659a512..3bf4409 100644
--- a/Source/QtDialog/QCMakeCacheView.cxx
+++ b/Source/QtDialog/QCMakeCacheView.cxx
@@ -220,8 +220,9 @@
 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
     QSet<QCMakeProperty> oldProps = this->properties().toSet();
 #else
-    QSet<QCMakeProperty> oldProps = QSet<QCMakeProperty>(
-      this->properties().begin(), this->properties().end());
+    QCMakePropertyList const& oldPropsList = this->properties();
+    QSet<QCMakeProperty> oldProps =
+      QSet<QCMakeProperty>(oldPropsList.begin(), oldPropsList.end());
 #endif
     oldProps.intersect(newProps);
     newProps.subtract(oldProps);
diff --git a/Source/cmBinUtilsMacOSMachOLinker.cxx b/Source/cmBinUtilsMacOSMachOLinker.cxx
index 98250b1..0f47146 100644
--- a/Source/cmBinUtilsMacOSMachOLinker.cxx
+++ b/Source/cmBinUtilsMacOSMachOLinker.cxx
@@ -14,6 +14,18 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
+namespace {
+bool IsMissingSystemDylib(std::string const& path)
+{
+  // Starting on macOS 11, the dynamic loader has a builtin cache of
+  // system-provided dylib files that do not exist on the filesystem.
+  // Tell our caller that these are expected to be missing.
+  return ((cmHasLiteralPrefix(path, "/System/Library/") ||
+           cmHasLiteralPrefix(path, "/usr/lib/")) &&
+          !cmSystemTools::PathExists(path));
+}
+}
+
 cmBinUtilsMacOSMachOLinker::cmBinUtilsMacOSMachOLinker(
   cmRuntimeDependencyArchive* archive)
   : cmBinUtilsLinker(archive)
@@ -82,7 +94,8 @@
         return false;
       }
       if (resolved) {
-        if (!this->Archive->IsPostExcluded(path)) {
+        if (!this->Archive->IsPostExcluded(path) &&
+            !IsMissingSystemDylib(path)) {
           auto filename = cmSystemTools::GetFilenameName(path);
           bool unique;
           this->Archive->AddResolvedPath(filename, path, unique);
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index 35bd681..95686ea 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -578,10 +578,7 @@
 bool cmCacheManager::CacheEntry::GetPropertyAsBool(
   const std::string& prop) const
 {
-  if (cmProp value = this->GetProperty(prop)) {
-    return cmIsOn(*value);
-  }
-  return false;
+  return cmIsOn(this->GetProperty(prop));
 }
 
 void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 051eff6..8aee27c 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -41,7 +41,7 @@
 const char* cmCommonTargetGenerator::GetFeature(const std::string& feature,
                                                 const std::string& config)
 {
-  return this->GeneratorTarget->GetFeature(feature, config);
+  return this->GeneratorTarget->GetFeature(feature, config)->c_str();
 }
 
 void cmCommonTargetGenerator::AddModuleDefinitionFlag(
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 4c5f57d..fbb95e1 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -515,7 +515,7 @@
   // Restore the target link type so the correct system runtime
   // libraries are found.
   cmProp lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
-  if (lss && cmIsOn(*lss)) {
+  if (cmIsOn(lss)) {
     this->SetCurrentLinkType(LinkStatic);
   } else {
     this->SetCurrentLinkType(this->StartLinkType);
@@ -841,7 +841,7 @@
 
   // Lookup the starting link type from the target (linked statically?).
   cmProp lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
-  this->StartLinkType = (lss && cmIsOn(*lss)) ? LinkStatic : LinkShared;
+  this->StartLinkType = cmIsOn(lss) ? LinkStatic : LinkShared;
   this->CurrentLinkType = this->StartLinkType;
 }
 
@@ -849,31 +849,31 @@
 {
   // Get possible library name prefixes.
   cmMakefile* mf = this->Makefile;
-  this->AddLinkPrefix(mf->GetDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
-  this->AddLinkPrefix(mf->GetDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
+  this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
+  this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
 
   // Import library names should be matched and treated as shared
   // libraries for the purposes of linking.
-  this->AddLinkExtension(mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
+  this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
                          LinkShared);
-  this->AddLinkExtension(mf->GetDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
+  this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
                          LinkStatic);
-  this->AddLinkExtension(mf->GetDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
+  this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
                          LinkShared);
-  this->AddLinkExtension(mf->GetDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
+  this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
                          LinkUnknown);
   if (const char* linkSuffixes =
         mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
     std::vector<std::string> linkSuffixVec = cmExpandedList(linkSuffixes);
     for (std::string const& i : linkSuffixVec) {
-      this->AddLinkExtension(i.c_str(), LinkUnknown);
+      this->AddLinkExtension(i, LinkUnknown);
     }
   }
   if (const char* sharedSuffixes =
         mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
     std::vector<std::string> sharedSuffixVec = cmExpandedList(sharedSuffixes);
     for (std::string const& i : sharedSuffixVec) {
-      this->AddLinkExtension(i.c_str(), LinkShared);
+      this->AddLinkExtension(i, LinkShared);
     }
   }
 
@@ -903,7 +903,7 @@
 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
   fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
 #endif
-  this->ExtractAnyLibraryName.compile(reg_any.c_str());
+  this->ExtractAnyLibraryName.compile(reg_any);
 
   // Create a regex to match static library names.
   if (!this->StaticLinkExtensions.empty()) {
@@ -912,7 +912,7 @@
 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
     fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
 #endif
-    this->ExtractStaticLibraryName.compile(reg_static.c_str());
+    this->ExtractStaticLibraryName.compile(reg_static);
   }
 
   // Create a regex to match shared library names.
@@ -924,20 +924,21 @@
 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
     fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
 #endif
-    this->ExtractSharedLibraryName.compile(reg_shared.c_str());
+    this->ExtractSharedLibraryName.compile(reg_shared);
   }
 }
 
-void cmComputeLinkInformation::AddLinkPrefix(const char* p)
+void cmComputeLinkInformation::AddLinkPrefix(std::string const& p)
 {
-  if (p && *p) {
+  if (!p.empty()) {
     this->LinkPrefixes.insert(p);
   }
 }
 
-void cmComputeLinkInformation::AddLinkExtension(const char* e, LinkType type)
+void cmComputeLinkInformation::AddLinkExtension(std::string const& e,
+                                                LinkType type)
 {
-  if (e && *e) {
+  if (!e.empty()) {
     if (type == LinkStatic) {
       this->StaticLinkExtensions.emplace_back(e);
     }
@@ -962,7 +963,7 @@
     // Store this extension choice with the "." escaped.
     libext += "\\";
 #if defined(_WIN32) && !defined(__CYGWIN__)
-    libext += this->NoCaseExpression(i.c_str());
+    libext += this->NoCaseExpression(i);
 #else
     libext += i;
 #endif
@@ -980,21 +981,19 @@
   return libext;
 }
 
-std::string cmComputeLinkInformation::NoCaseExpression(const char* str)
+std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str)
 {
   std::string ret;
-  ret.reserve(strlen(str) * 4);
-  const char* s = str;
-  while (*s) {
-    if (*s == '.') {
-      ret += *s;
+  ret.reserve(str.size() * 4);
+  for (char c : str) {
+    if (c == '.') {
+      ret += c;
     } else {
       ret += '[';
-      ret += static_cast<char>(tolower(*s));
-      ret += static_cast<char>(toupper(*s));
+      ret += static_cast<char>(tolower(c));
+      ret += static_cast<char>(toupper(c));
       ret += ']';
     }
-    s++;
   }
   return ret;
 }
@@ -1688,7 +1687,7 @@
   }
 }
 
-static void cmCLI_ExpandListUnique(const char* str,
+static void cmCLI_ExpandListUnique(std::string const& str,
                                    std::vector<std::string>& out,
                                    std::set<std::string>& emitted)
 {
@@ -1735,7 +1734,7 @@
   if (use_install_rpath) {
     std::string install_rpath;
     this->Target->GetInstallRPATH(this->Config, install_rpath);
-    cmCLI_ExpandListUnique(install_rpath.c_str(), runtimeDirs, emitted);
+    cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
   }
   if (use_build_rpath) {
     // Add directories explicitly specified by user
@@ -1743,7 +1742,7 @@
     if (this->Target->GetBuildRPATH(this->Config, build_rpath)) {
       // This will not resolve entries to use $ORIGIN, the user is expected to
       // do that if necessary.
-      cmCLI_ExpandListUnique(build_rpath.c_str(), runtimeDirs, emitted);
+      cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted);
     }
   }
   if (use_build_rpath || use_link_rpath) {
@@ -1823,8 +1822,8 @@
         "CMAKE_" + li + "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH";
       if (this->Makefile->IsOn(useVar)) {
         std::string dirVar = "CMAKE_" + li + "_IMPLICIT_LINK_DIRECTORIES";
-        if (const char* dirs = this->Makefile->GetDefinition(dirVar)) {
-          cmCLI_ExpandListUnique(dirs, runtimeDirs, emitted);
+        if (cmProp dirs = this->Makefile->GetDef(dirVar)) {
+          cmCLI_ExpandListUnique(*dirs, runtimeDirs, emitted);
         }
       }
     }
@@ -1832,7 +1831,7 @@
 
   // Add runtime paths required by the platform to always be
   // present.  This is done even when skipping rpath support.
-  cmCLI_ExpandListUnique(this->RuntimeAlways.c_str(), runtimeDirs, emitted);
+  cmCLI_ExpandListUnique(this->RuntimeAlways, runtimeDirs, emitted);
 }
 
 std::string cmComputeLinkInformation::GetRPathString(bool for_install) const
diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h
index e50d369..544ff23 100644
--- a/Source/cmComputeLinkInformation.h
+++ b/Source/cmComputeLinkInformation.h
@@ -144,11 +144,11 @@
   cmsys::RegularExpression ExtractSharedLibraryName;
   cmsys::RegularExpression ExtractAnyLibraryName;
   std::string SharedRegexString;
-  void AddLinkPrefix(const char* p);
-  void AddLinkExtension(const char* e, LinkType type);
+  void AddLinkPrefix(std::string const& p);
+  void AddLinkExtension(std::string const& e, LinkType type);
   std::string CreateExtensionRegex(std::vector<std::string> const& exts,
                                    LinkType type);
-  std::string NoCaseExpression(const char* str);
+  std::string NoCaseExpression(std::string const& str);
 
   // Handling of link items.
   void AddTargetItem(BT<std::string> const& item,
diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in
index 4de1c5d..97e7856 100644
--- a/Source/cmConfigure.cmake.h.in
+++ b/Source/cmConfigure.cmake.h.in
@@ -19,7 +19,6 @@
 #cmakedefine HAVE_UNSETENV
 #cmakedefine CMAKE_USE_ELF_PARSER
 #cmakedefine CMAKE_USE_MACH_PARSER
-#cmakedefine CMake_HAVE_CXX_MAKE_UNIQUE
 #define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@
 #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@"
 #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@"
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 7fbe90e..8465c58 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -18,6 +18,7 @@
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
 #include "cmState.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -235,9 +236,8 @@
   this->SrcFileSignature = true;
 
   cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
-  const std::string* tt =
-    this->Makefile->GetDef("CMAKE_TRY_COMPILE_TARGET_TYPE");
-  if (!isTryRun && tt && !tt->empty()) {
+  cmProp tt = this->Makefile->GetDef("CMAKE_TRY_COMPILE_TARGET_TYPE");
+  if (!isTryRun && cmNonempty(tt)) {
     if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
       targetType = cmStateEnums::EXECUTABLE;
     } else if (*tt ==
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index 652c041..be22ad4 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -236,9 +236,8 @@
       //
       // Also we can disable external (outside the project) files by setting ON
       // CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable.
-      const bool excludeExternal =
-        cmIsOn(it.second[0]->GetMakefile()->GetSafeDefinition(
-          "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES"));
+      const bool excludeExternal = it.second[0]->GetMakefile()->IsOn(
+        "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES");
       if (!splitted.empty() &&
           (!excludeExternal || (relative.find("..") == std::string::npos)) &&
           relative.find("CMakeFiles") == std::string::npos) {
@@ -380,9 +379,8 @@
               cmSystemTools::RelativePath(lg->GetSourceDirectory(), fullPath);
             // Do not add this file if it has ".." in relative path and
             // if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on.
-            const bool excludeExternal =
-              cmIsOn(lg->GetMakefile()->GetSafeDefinition(
-                "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES"));
+            const bool excludeExternal = lg->GetMakefile()->IsOn(
+              "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES");
             if (excludeExternal &&
                 (relative.find("..") != std::string::npos)) {
               continue;
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 8d5b177..ae06047 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -1121,7 +1121,7 @@
   std::vector<std::string> foundContents;
   cmProp foundProp =
     this->Makefile->GetState()->GetGlobalProperty("PACKAGES_FOUND");
-  if (foundProp && !foundProp->empty()) {
+  if (cmNonempty(foundProp)) {
     cmExpandList(*foundProp, foundContents, false);
     auto nameIt =
       std::find(foundContents.begin(), foundContents.end(), this->Name);
@@ -1133,7 +1133,7 @@
   std::vector<std::string> notFoundContents;
   cmProp notFoundProp =
     this->Makefile->GetState()->GetGlobalProperty("PACKAGES_NOT_FOUND");
-  if (notFoundProp && !notFoundProp->empty()) {
+  if (cmNonempty(notFoundProp)) {
     cmExpandList(*notFoundProp, notFoundContents, false);
     auto nameIt =
       std::find(notFoundContents.begin(), notFoundContents.end(), this->Name);
@@ -1166,9 +1166,9 @@
   std::string found = cmStrCat(this->Name, "_FOUND");
   std::string upperFound = cmSystemTools::UpperCase(found);
 
-  const char* upperResult = this->Makefile->GetDefinition(upperFound);
-  const char* result = this->Makefile->GetDefinition(found);
-  bool packageFound = ((cmIsOn(result)) || (cmIsOn(upperResult)));
+  bool upperResult = this->Makefile->IsOn(upperFound);
+  bool result = this->Makefile->IsOn(found);
+  bool packageFound = (result || upperResult);
 
   this->AppendToFoundProperty(packageFound);
 
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 6e293d5..840f511 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -406,9 +406,3 @@
     this->LocalGenerator, this->Config, this->HeadTarget, &dagChecker, nullptr,
     this->Language);
 }
-
-const std::string& cmGeneratorExpressionInterpreter::Evaluate(
-  const char* expression, const std::string& property)
-{
-  return this->Evaluate(std::string(expression ? expression : ""), property);
-}
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 75bba02..09d8b88 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -199,8 +199,6 @@
 
   const std::string& Evaluate(std::string expression,
                               const std::string& property);
-  const std::string& Evaluate(const char* expression,
-                              const std::string& property);
 
 protected:
   cmGeneratorExpression GeneratorExpression;
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index 4f379cd..e223f15 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -154,6 +154,14 @@
   return this->Top()->Property == "INTERFACE_POSITION_INDEPENDENT_CODE";
 }
 
+bool cmGeneratorExpressionDAGChecker::EvaluatingCompileExpression() const
+{
+  cm::string_view property(this->Top()->Property);
+
+  return property == "INCLUDE_DIRECTORIES"_s ||
+    property == "COMPILE_DEFINITIONS"_s || property == "COMPILE_OPTIONS"_s;
+}
+
 bool cmGeneratorExpressionDAGChecker::EvaluatingLinkExpression() const
 {
   cm::string_view property(this->Top()->Property);
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index c2c5b6b..ac2314c 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -68,6 +68,7 @@
 
   bool EvaluatingGenexExpression() const;
   bool EvaluatingPICExpression() const;
+  bool EvaluatingCompileExpression() const;
   bool EvaluatingLinkExpression() const;
   bool EvaluatingLinkOptionsExpression() const;
 
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 4adc6a2..fdc8f29 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -967,9 +967,10 @@
     const std::vector<std::string>& parameters,
     cmGeneratorExpressionContext* context,
     const GeneratorExpressionContent* content,
-    cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
   {
-    if (context->Language.empty()) {
+    if (context->Language.empty() &&
+        (!dagChecker || !dagChecker->EvaluatingCompileExpression())) {
       reportError(
         context, content->GetOriginalExpression(),
         "$<COMPILE_LANGUAGE:...> may only be used to specify include "
@@ -1014,7 +1015,9 @@
     const GeneratorExpressionContent* content,
     cmGeneratorExpressionDAGChecker* dagChecker) const override
   {
-    if (!context->HeadTarget || context->Language.empty()) {
+    if (!context->HeadTarget ||
+        (context->Language.empty() &&
+         (!dagChecker || !dagChecker->EvaluatingCompileExpression()))) {
       // reportError(context, content->GetOriginalExpression(), "");
       reportError(
         context, content->GetOriginalExpression(),
@@ -1473,8 +1476,9 @@
     }
 
     if (isInterfaceProperty) {
-      return target->EvaluateInterfaceProperty(propertyName, context,
-                                               dagCheckerParent);
+      return cmGeneratorExpression::StripEmptyListElements(
+        target->EvaluateInterfaceProperty(propertyName, context,
+                                          dagCheckerParent));
     }
 
     cmGeneratorExpressionDAGChecker dagChecker(
@@ -1560,8 +1564,9 @@
     }
 
     if (!interfacePropertyName.empty()) {
-      result = this->EvaluateDependentExpression(result, context->LG, context,
-                                                 target, &dagChecker, target);
+      result = cmGeneratorExpression::StripEmptyListElements(
+        this->EvaluateDependentExpression(result, context->LG, context, target,
+                                          &dagChecker, target));
       std::string linkedTargetsContent = getLinkedTargetsContent(
         target, interfacePropertyName, context, &dagChecker);
       if (!linkedTargetsContent.empty()) {
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index ccd8e7e..4fe68d2 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -365,7 +365,7 @@
 {
   cmProp exportName = this->GetProperty("EXPORT_NAME");
 
-  if (exportName && !exportName->empty()) {
+  if (cmNonempty(exportName)) {
     if (!cmGeneratorExpression::IsValidTargetName(*exportName)) {
       std::ostringstream e;
       e << "EXPORT_NAME property \"" << *exportName << "\" for \""
@@ -815,18 +815,18 @@
   }
 }
 
-const char* cmGeneratorTarget::GetFeature(const std::string& feature,
-                                          const std::string& config) const
+cmProp cmGeneratorTarget::GetFeature(const std::string& feature,
+                                     const std::string& config) const
 {
   if (!config.empty()) {
     std::string featureConfig =
       cmStrCat(feature, '_', cmSystemTools::UpperCase(config));
     if (cmProp value = this->GetProperty(featureConfig)) {
-      return value->c_str();
+      return value;
     }
   }
   if (cmProp value = this->GetProperty(feature)) {
-    return value->c_str();
+    return value;
   }
   return this->LocalGenerator->GetFeature(feature, config);
 }
@@ -853,10 +853,9 @@
 bool cmGeneratorTarget::IsIPOEnabled(std::string const& lang,
                                      std::string const& config) const
 {
-  const char* feature = "INTERPROCEDURAL_OPTIMIZATION";
-  const bool result = cmIsOn(this->GetFeature(feature, config));
+  cmProp feature = this->GetFeature("INTERPROCEDURAL_OPTIMIZATION", config);
 
-  if (!result) {
+  if (!cmIsOn(feature)) {
     // 'INTERPROCEDURAL_OPTIMIZATION' is off, no need to check policies
     return false;
   }
@@ -1001,7 +1000,7 @@
 {
   cmProp p =
     this->GetPropertyWithPairedLanguageSupport(lang, "_STANDARD_REQUIRED");
-  return p && cmIsOn(*p);
+  return cmIsOn(p);
 }
 
 void cmGeneratorTarget::GetModuleDefinitionSources(
@@ -1194,7 +1193,7 @@
 
     // If this target itself has a non-empty property value, we are done.
     cmProp p = this->GetProperty(prop);
-    maybeInterfaceProp = p && !p->empty();
+    maybeInterfaceProp = cmNonempty(p);
 
     // Otherwise, recurse to interface dependencies.
     if (!maybeInterfaceProp) {
@@ -1366,6 +1365,9 @@
 
     for (const cmLinkImplItem& library : libraries->Libraries) {
       if (const cmGeneratorTarget* dependency = library.Target) {
+        if (dependency->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+          continue;
+        }
         if (cm::contains(dependency->GetAllConfigCompileLanguages(),
                          "Swift")) {
           EvaluatedTargetPropertyEntry entry{ library, library.Backtrace };
@@ -1841,12 +1843,12 @@
   std::string configUpper = cmSystemTools::UpperCase(config);
   std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper);
   cmProp config_name = this->GetProperty(configProp);
-  if (config_name && !config_name->empty()) {
+  if (cmNonempty(config_name)) {
     return prefix + *config_name + ".pdb";
   }
 
   cmProp name = this->GetProperty("COMPILE_PDB_NAME");
-  if (name && !name->empty()) {
+  if (cmNonempty(name)) {
     return prefix + *name + ".pdb";
   }
 
@@ -2293,7 +2295,7 @@
     cmProp install_name_dir = this->GetProperty("INSTALL_NAME_DIR");
 
     if (this->CanGenerateInstallNameDir(INSTALL_NAME_FOR_INSTALL)) {
-      if (install_name_dir && !install_name_dir->empty()) {
+      if (cmNonempty(install_name_dir)) {
         dir = *install_name_dir;
         cmGeneratorExpression::ReplaceInstallPrefix(dir, installPrefix);
         dir =
@@ -5411,8 +5413,7 @@
   }
 
   cmProp value = tgt->GetProperty(prop);
-  return cmIsOn(
-    genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop));
+  return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop));
 }
 
 template <>
@@ -5426,8 +5427,7 @@
     return value ? value->c_str() : nullptr;
   }
 
-  return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop)
-    .c_str();
+  return genexInterpreter->Evaluate(value ? *value : "", prop).c_str();
 }
 
 template <>
@@ -5441,7 +5441,7 @@
     return valueAsString(value ? value->c_str() : nullptr);
   }
 
-  return genexInterpreter->Evaluate(value ? value->c_str() : nullptr, prop);
+  return genexInterpreter->Evaluate(value ? *value : "", prop);
 }
 
 template <typename PropertyType>
@@ -5842,7 +5842,7 @@
   // not it is overridden by a property.
   cmProp runtimeLibraryDefault = this->Makefile->GetDef(
     cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"));
-  if (!runtimeLibraryDefault || runtimeLibraryDefault->empty()) {
+  if (!cmNonempty(runtimeLibraryDefault)) {
     return std::string();
   }
   cmProp runtimeLibraryValue =
@@ -6975,7 +6975,7 @@
 bool cmGeneratorTarget::IsDeprecated() const
 {
   cmProp deprecation = this->GetProperty("DEPRECATION");
-  return deprecation && !deprecation->empty();
+  return cmNonempty(deprecation);
 }
 
 std::string cmGeneratorTarget::GetDeprecation() const
@@ -7040,7 +7040,7 @@
   // Consider an explicit linker language property, but *not* the
   // computed linker language that may depend on linked targets.
   cmProp linkLang = this->GetProperty("LINKER_LANGUAGE");
-  if (linkLang && !linkLang->empty()) {
+  if (cmNonempty(linkLang)) {
     languages.insert(*linkLang);
   }
   return languages.size() == 1 && languages.count("CSharp") > 0;
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 07f071b..08aa015 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -175,8 +175,8 @@
 
   void ComputeObjectMapping();
 
-  const char* GetFeature(const std::string& feature,
-                         const std::string& config) const;
+  cmProp GetFeature(const std::string& feature,
+                    const std::string& config) const;
 
   const char* GetLinkPIEProperty(const std::string& config) const;
 
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 358d65a..1589c47 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -550,9 +550,9 @@
    */
   for (auto& sg : groupFilesList) {
     std::ostream* fout;
-    bool useProjectFile = cmIsOn(*this->GeneratorTarget->GetProperty(
-                            "GHS_NO_SOURCE_GROUP_FILE")) ||
-      cmIsOn(this->Makefile->GetDefinition("CMAKE_GHS_NO_SOURCE_GROUP_FILE"));
+    bool useProjectFile =
+      cmIsOn(this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) ||
+      this->Makefile->IsOn("CMAKE_GHS_NO_SOURCE_GROUP_FILE");
     if (useProjectFile || sg.empty()) {
       fout = &fout_proj;
     } else {
diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx
index 9dc86f4..5eff3b8 100644
--- a/Source/cmGlobalCommonGenerator.cxx
+++ b/Source/cmGlobalCommonGenerator.cxx
@@ -5,8 +5,12 @@
 #include <memory>
 #include <utility>
 
+#include <cmext/algorithm>
+
+#include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmLocalGenerator.h"
+#include "cmMakefile.h"
 #include "cmProperty.h"
 #include "cmStateDirectory.h"
 #include "cmStateSnapshot.h"
@@ -31,6 +35,8 @@
       lg->GetStateSnapshot().GetDirectory().GetCurrentBinary());
     DirectoryTarget& dirTarget = dirTargets[currentBinaryDir];
     dirTarget.LG = lg.get();
+    const std::vector<std::string>& configs =
+      lg->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
 
     // The directory-level rule should depend on the target-level rules
     // for all targets in the directory.
@@ -46,11 +52,18 @@
       }
       DirectoryTarget::Target t;
       t.GT = gt.get();
-      if (cmProp exclude = gt->GetProperty("EXCLUDE_FROM_ALL")) {
-        if (cmIsOn(*exclude)) {
-          // This target has been explicitly excluded.
-          t.ExcludeFromAll = true;
-        } else {
+      const std::string EXCLUDE_FROM_ALL("EXCLUDE_FROM_ALL");
+      if (cmProp exclude = gt->GetProperty(EXCLUDE_FROM_ALL)) {
+        for (const std::string& config : configs) {
+          cmGeneratorExpressionInterpreter genexInterpreter(lg.get(), config,
+                                                            gt.get());
+          if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
+            // This target has been explicitly excluded.
+            t.ExcludedFromAllInConfigs.push_back(config);
+          }
+        }
+
+        if (t.ExcludedFromAllInConfigs.empty()) {
           // This target has been explicitly un-excluded.  The directory-level
           // rule for every directory between this and the root should depend
           // on the target-level rule for this target.
@@ -78,3 +91,12 @@
 
   return dirTargets;
 }
+
+bool cmGlobalCommonGenerator::IsExcludedFromAllInConfig(
+  const DirectoryTarget::Target& t, const std::string& config)
+{
+  if (this->IsMultiConfig()) {
+    return cm::contains(t.ExcludedFromAllInConfigs, config);
+  }
+  return !t.ExcludedFromAllInConfigs.empty();
+}
diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h
index 7d16dac..f97b5f4 100644
--- a/Source/cmGlobalCommonGenerator.h
+++ b/Source/cmGlobalCommonGenerator.h
@@ -30,7 +30,7 @@
     struct Target
     {
       cmGeneratorTarget const* GT = nullptr;
-      bool ExcludeFromAll = false;
+      std::vector<std::string> ExcludedFromAllInConfigs;
     };
     std::vector<Target> Targets;
     struct Dir
@@ -41,6 +41,8 @@
     std::vector<Dir> Children;
   };
   std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const;
+  bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t,
+                                 const std::string& config);
 };
 
 #endif
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index a0cee0e..d39fefa 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -304,14 +304,10 @@
     for (const auto& target : localGen->GetGeneratorTargets()) {
       if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
           target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
-          target->GetType() == cmStateEnums::TargetType::UTILITY) {
+          target->GetType() == cmStateEnums::TargetType::UTILITY ||
+          cmIsOn(target->GetProperty("ghs_integrity_app"))) {
         continue;
       }
-      if (cmProp p = target->GetProperty("ghs_integrity_app")) {
-        if (cmIsOn(*p)) {
-          continue;
-        }
-      }
 
       std::vector<std::string> configs =
         target->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
@@ -374,14 +370,10 @@
     for (const auto& target : generator->GetGeneratorTargets()) {
       if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
           target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
-          target->GetType() == cmStateEnums::TargetType::UTILITY) {
+          target->GetType() == cmStateEnums::TargetType::UTILITY ||
+          cmIsOn(target->GetProperty("ghs_integrity_app"))) {
         continue;
       }
-      if (cmProp p = target->GetProperty("ghs_integrity_app")) {
-        if (cmIsOn(*p)) {
-          continue;
-        }
-      }
 
       std::string const& reuseFrom =
         target->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM");
@@ -2181,13 +2173,38 @@
 }
 
 bool cmGlobalGenerator::IsExcluded(cmLocalGenerator* root,
-                                   cmGeneratorTarget* target) const
+                                   const cmGeneratorTarget* target) const
 {
   if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
     return true;
   }
-  if (cmProp exclude = target->GetProperty("EXCLUDE_FROM_ALL")) {
-    return cmIsOn(*exclude);
+  cmMakefile* mf = root->GetMakefile();
+  const std::string EXCLUDE_FROM_ALL = "EXCLUDE_FROM_ALL";
+  if (cmProp exclude = target->GetProperty(EXCLUDE_FROM_ALL)) {
+    // Expand the property value per configuration.
+    unsigned int trueCount = 0;
+    unsigned int falseCount = 0;
+    const std::vector<std::string>& configs =
+      mf->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+    for (const std::string& config : configs) {
+      cmGeneratorExpressionInterpreter genexInterpreter(root, config, target);
+      if (cmIsOn(genexInterpreter.Evaluate(*exclude, EXCLUDE_FROM_ALL))) {
+        ++trueCount;
+      } else {
+        ++falseCount;
+      }
+    }
+
+    // Check whether the genex expansion of the property agrees in all
+    // configurations.
+    if (trueCount && falseCount) {
+      std::ostringstream e;
+      e << "The EXCLUDED_FROM_ALL property of target \"" << target->GetName()
+        << "\" varies by configuration. This is not supported by the \""
+        << root->GetGlobalGenerator()->GetName() << "\" generator.";
+      mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    }
+    return trueCount;
   }
   // This target is included in its directory.  Check whether the
   // directory is excluded.
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index 57c7808..c2c80c2 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -542,7 +542,8 @@
   bool IsExcluded(cmStateSnapshot const& root,
                   cmStateSnapshot const& snp) const;
   bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const;
-  bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const;
+  bool IsExcluded(cmLocalGenerator* root,
+                  const cmGeneratorTarget* target) const;
   virtual void InitializeProgressMarks() {}
 
   struct GlobalTargetInfo
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index d36adfb..1664dd0 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -470,8 +470,7 @@
     if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
       continue;
     }
-    cmProp p = t->GetProperty("EXCLUDE_FROM_ALL");
-    if (!(p && cmIsOn(*p))) {
+    if (!IsExcluded(t->GetLocalGenerator(), t)) {
       defaultTargets.push_back(t);
     }
   }
@@ -635,7 +634,7 @@
   std::string tgt;
   const char* t =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET");
-  if (t && *t != '\0') {
+  if (cmNonempty(t)) {
     tgt = t;
     this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET");
   } else {
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 48eb405..786cde7 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1357,7 +1357,7 @@
       build.Outputs.front() = this->BuildAlias(buildDirAllTarget, config);
       configDeps.emplace_back(build.Outputs.front());
       for (DirectoryTarget::Target const& t : dt.Targets) {
-        if (!t.ExcludeFromAll) {
+        if (!IsExcludedFromAllInConfig(t, config)) {
           this->AppendTargetOutputs(t.GT, build.ExplicitDeps, config);
         }
       }
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index c31983b..d45fc01 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -416,7 +416,7 @@
   std::vector<std::string> depends;
   for (DirectoryTarget::Target const& t : dt.Targets) {
     // Add this to the list of depends rules in this directory.
-    if ((!check_all || !t.ExcludeFromAll) &&
+    if ((!check_all || t.ExcludedFromAllInConfigs.empty()) &&
         (!check_relink ||
          t.GT->NeedRelinkBeforeInstall(lg->GetConfigName()))) {
       // The target may be from a different directory; use its local gen.
@@ -846,7 +846,7 @@
       cmLocalGenerator* tlg = gt->GetLocalGenerator();
 
       if (gt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
-          gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
+          IsExcluded(lg.get(), gt.get())) {
         continue;
       }
 
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 9f798e6..c851eea 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -694,9 +694,7 @@
   }
   // inspect EXCLUDE_FROM_DEFAULT_BUILD[_<CONFIG>] properties
   for (std::string const& i : configs) {
-    const char* propertyValue =
-      target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i);
-    if (cmIsOff(propertyValue)) {
+    if (cmIsOff(target->GetFeature("EXCLUDE_FROM_DEFAULT_BUILD", i))) {
       activeConfigs.insert(i);
     }
   }
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index c688da2..b31d069 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -509,7 +509,7 @@
   cmLocalGenerator const* root) const
 {
   cmProp n = root->GetMakefile()->GetProperty("VS_STARTUP_PROJECT");
-  if (n && !n->empty()) {
+  if (cmNonempty(n)) {
     std::string startup = *n;
     if (this->FindTarget(startup)) {
       return startup;
@@ -810,7 +810,7 @@
   // a target with none of its own sources, e.g. when also using
   // object libraries.
   cmProp linkLang = gt->GetProperty("LINKER_LANGUAGE");
-  if (linkLang && !linkLang->empty()) {
+  if (cmNonempty(linkLang)) {
     languages.insert(*linkLang);
   }
 
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 656a346..e54de5d 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -12,6 +12,7 @@
 
 #include <cm/memory>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include "cmsys/RegularExpression.hxx"
 
@@ -172,6 +173,7 @@
 
   this->RootObject = nullptr;
   this->MainGroupChildren = nullptr;
+  this->FrameworkGroup = nullptr;
   this->CurrentMakefile = nullptr;
   this->CurrentLocalGenerator = nullptr;
   this->XcodeBuildCommandInitialized = false;
@@ -271,6 +273,13 @@
   return makeProgram;
 }
 
+bool cmGlobalXCodeGenerator::SetSystemName(std::string const& s,
+                                           cmMakefile* mf)
+{
+  this->SystemName = s;
+  return this->cmGlobalGenerator::SetSystemName(s, mf);
+}
+
 bool cmGlobalXCodeGenerator::SetGeneratorToolset(std::string const& ts,
                                                  bool build, cmMakefile* mf)
 {
@@ -668,6 +677,7 @@
   this->GroupNameMap.clear();
   this->TargetGroup.clear();
   this->FileRefs.clear();
+  this->ExternalLibRefs.clear();
 }
 
 void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj)
@@ -736,7 +746,7 @@
   return key;
 }
 
-cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath(
+cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeBuildFileFromPath(
   const std::string& fullpath, cmGeneratorTarget* target,
   const std::string& lang, cmSourceFile* sf)
 {
@@ -872,7 +882,7 @@
   lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true));
 
   cmXCodeObject* buildFile =
-    this->CreateXCodeSourceFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf);
+    this->CreateXCodeBuildFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf);
 
   cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
   settings->AddAttributeIfNotEmpty("COMPILER_FLAGS",
@@ -925,6 +935,31 @@
   }
 }
 
+bool IsLibraryExtension(const std::string& fileExt)
+{
+  return (fileExt == ".framework" || fileExt == ".a" || fileExt == ".o" ||
+          fileExt == ".dylib" || fileExt == ".tbd");
+}
+bool IsLibraryType(const std::string& fileType)
+{
+  return (fileType == "wrapper.framework" || fileType == "archive.ar" ||
+          fileType == "compiled.mach-o.objfile" ||
+          fileType == "compiled.mach-o.dylib" ||
+          fileType == "sourcecode.text-based-dylib-definition");
+}
+
+std::string GetDirectoryValueFromFileExtension(const std::string& dirExt)
+{
+  std::string ext = cmSystemTools::LowerCase(dirExt);
+  if (ext == "framework") {
+    return "wrapper.framework";
+  }
+  if (ext == "xcassets") {
+    return "folder.assetcatalog";
+  }
+  return "folder";
+}
+
 std::string GetSourcecodeValueFromFileExtension(
   const std::string& _ext, const std::string& lang,
   bool& keepLastKnownFileType, const std::vector<std::string>& enabled_langs)
@@ -933,6 +968,7 @@
   std::string sourcecode = "sourcecode";
 
   if (ext == "o") {
+    keepLastKnownFileType = true;
     sourcecode = "compiled.mach-o.objfile";
   } else if (ext == "xctest") {
     sourcecode = "wrapper.cfbundle";
@@ -976,6 +1012,14 @@
     sourcecode += ".metal";
   } else if (ext == "mig") {
     sourcecode += ".mig";
+  } else if (ext == "tbd") {
+    sourcecode += ".text-based-dylib-definition";
+  } else if (ext == "a") {
+    keepLastKnownFileType = true;
+    sourcecode = "archive.ar";
+  } else if (ext == "dylib") {
+    keepLastKnownFileType = true;
+    sourcecode = "compiled.mach-o.dylib";
   }
   // else
   //  {
@@ -992,20 +1036,6 @@
   const std::string& fullpath, cmGeneratorTarget* target,
   const std::string& lang, cmSourceFile* sf)
 {
-  std::string key = GetGroupMapKeyFromPath(target, fullpath);
-  cmXCodeObject* fileRef = this->FileRefs[key];
-  if (!fileRef) {
-    fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
-    fileRef->SetComment(fullpath);
-    this->FileRefs[key] = fileRef;
-  }
-  cmXCodeObject* group = this->GroupMap[key];
-  cmXCodeObject* children = group->GetObject("children");
-  if (!children->HasObject(fileRef)) {
-    children->AddObject(fileRef);
-  }
-  fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
-
   bool useLastKnownFileType = false;
   std::string fileType;
   if (sf) {
@@ -1016,19 +1046,32 @@
       fileType = *l;
     }
   }
+  // Make a copy so that we can override it later
+  std::string path = fullpath;
+  // Compute the extension without leading '.'.
+  std::string ext = cmSystemTools::GetFilenameLastExtension(path);
+  if (!ext.empty()) {
+    ext = ext.substr(1);
+  }
   if (fileType.empty()) {
-    // Compute the extension without leading '.'.
-    std::string ext = cmSystemTools::GetFilenameLastExtension(fullpath);
-    if (!ext.empty()) {
-      ext = ext.substr(1);
+    // If file has no extension it's either a raw executable or might
+    // be a direct reference to binary within a framework (bad practice!)
+    // so this is where we change the path to the point to framework
+    // directory.
+    if (ext.empty()) {
+      auto parentDir = cmSystemTools::GetParentDirectory(path);
+      auto parentExt = cmSystemTools::GetFilenameLastExtension(parentDir);
+      if (parentExt == ".framework") {
+        path = parentDir;
+        ext = parentExt.substr(1);
+      }
     }
-
     // If fullpath references a directory, then we need to specify
     // lastKnownFileType as folder in order for Xcode to be able to
     // open the contents of the folder.
     // (Xcode 4.6 does not like explicitFileType=folder).
-    if (cmSystemTools::FileIsDirectory(fullpath)) {
-      fileType = (ext == "xcassets" ? "folder.assetcatalog" : "folder");
+    if (cmSystemTools::FileIsDirectory(path)) {
+      fileType = GetDirectoryValueFromFileExtension(ext);
       useLastKnownFileType = true;
     } else {
       fileType = GetSourcecodeValueFromFileExtension(
@@ -1036,18 +1079,37 @@
     }
   }
 
+  std::string key = GetGroupMapKeyFromPath(target, path);
+  cmXCodeObject* fileRef = this->FileRefs[key];
+  if (!fileRef) {
+    fileRef = this->CreateObject(cmXCodeObject::PBXFileReference);
+    fileRef->SetComment(path);
+    this->FileRefs[key] = fileRef;
+  }
+  fileRef->AddAttribute("fileEncoding", this->CreateString("4"));
   fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType"
                                              : "explicitFileType",
                         this->CreateString(fileType));
-
   // Store the file path relative to the top of the source tree.
-  std::string path = this->RelativeToSource(fullpath);
+  if (!IsLibraryType(fileType)) {
+    path = this->RelativeToSource(path);
+  }
   std::string name = cmSystemTools::GetFilenameName(path);
   const char* sourceTree =
     cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT";
   fileRef->AddAttribute("name", this->CreateString(name));
   fileRef->AddAttribute("path", this->CreateString(path));
   fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree));
+
+  cmXCodeObject* group = this->GroupMap[key];
+  if (!group && IsLibraryType(fileType)) {
+    group = this->FrameworkGroup;
+    this->GroupMap[key] = group;
+  }
+  cmXCodeObject* children = group->GetObject("children");
+  if (!children->HasObject(fileRef)) {
+    children->AddObject(fileRef);
+  }
   return fileRef;
 }
 
@@ -1182,11 +1244,14 @@
       this->CurrentLocalGenerator, sourceFile, gtgt);
     cmXCodeObject* fr = xsf->GetObject("fileRef");
     cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType");
+    if (!filetype) {
+      filetype = fr->GetObject()->GetObject("lastKnownFileType");
+    }
 
     cmGeneratorTarget::SourceFileFlags tsFlags =
       gtgt->GetTargetSourceFileFlags(sourceFile);
 
-    if (filetype && filetype->GetString() == "compiled.mach-o.objfile") {
+    if (filetype && IsLibraryType(filetype->GetString())) {
       if (sourceFile->GetObjectLibrary().empty()) {
         externalObjFiles.push_back(xsf);
       }
@@ -2800,21 +2865,30 @@
       continue;
     }
     for (auto const& libItem : cli->GetItems()) {
-      // TODO: Drop this check once we have option to add outside libraries to
-      // Xcode project
-      auto* libTarget = FindXCodeTarget(libItem.Target);
       if (gt->IsBundleOnApple() &&
           (gt->GetType() == cmStateEnums::EXECUTABLE ||
            gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
            gt->GetType() == cmStateEnums::MODULE_LIBRARY ||
            gt->GetType() == cmStateEnums::UNKNOWN_LIBRARY) &&
-          (libTarget && libItem.Target &&
-           (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
-            libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
-            libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY))) {
+          ((libItem.Target &&
+            (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
+             libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
+             libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY)) ||
+           (!libItem.Target && libItem.IsPath))) {
         // Add unique configuration name to target-config map for later
         // checks
-        std::string libName = libItem.Target->GetName();
+        std::string libName;
+        if (libItem.Target) {
+          libName = libItem.Target->GetName();
+        } else {
+          libName = cmSystemTools::GetFilenameName(libItem.Value.Value);
+          const auto libExt = cmSystemTools::GetFilenameExtension(libName);
+          if (!IsLibraryExtension(libExt)) {
+            // Add this library item to a regular linker flag list
+            addToLinkerArguments(configName, &libItem);
+            continue;
+          }
+        }
         auto& configVector = targetConfigMap[libName];
         if (std::find(configVector.begin(), configVector.end(), configName) ==
             configVector.end()) {
@@ -2865,38 +2939,63 @@
   std::vector<std::string> linkSearchPaths;
   for (auto const& libItem : linkPhaseTargetVector) {
     // Add target output directory as a library search path
-    std::string linkDir = cmSystemTools::GetParentDirectory(
-      libItem->Target->GetLocationForBuild());
+    std::string linkDir;
+    if (libItem->Target) {
+      linkDir = cmSystemTools::GetParentDirectory(
+        libItem->Target->GetLocationForBuild());
+    } else {
+      linkDir = cmSystemTools::GetParentDirectory(libItem->Value.Value);
+    }
     if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) ==
         linkSearchPaths.end()) {
       linkSearchPaths.push_back(linkDir);
     }
     // Add target dependency
-    auto const& libName = *libItem;
-    if (!libName.Target->IsImported()) {
+    if (libItem->Target && !libItem->Target->IsImported()) {
       for (auto const& configName : this->CurrentConfigurationTypes) {
-        target->AddDependTarget(configName, libName.Target->GetName());
+        target->AddDependTarget(configName, libItem->Target->GetName());
       }
     }
     // Get the library target
     auto* libTarget = FindXCodeTarget(libItem->Target);
-    if (!libTarget) {
-      continue;
-    }
-    // Add the target output file as a build reference for other targets
-    // to link against
-    auto* fileRefObject = libTarget->GetObject("productReference");
-    if (!fileRefObject) {
-      continue;
-    }
     cmXCodeObject* buildFile;
-    auto it = FileRefToBuildFileMap.find(fileRefObject);
-    if (it == FileRefToBuildFileMap.end()) {
-      buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
-      buildFile->AddAttribute("fileRef", fileRefObject);
-      FileRefToBuildFileMap[fileRefObject] = buildFile;
+    if (!libTarget) {
+      if (libItem->IsPath) {
+        // Get or create a direct file ref in the root project
+        auto it = this->ExternalLibRefs.find(libItem->Value.Value);
+        if (it == this->ExternalLibRefs.end()) {
+          buildFile = CreateXCodeBuildFileFromPath(libItem->Value.Value, gt,
+                                                   "", nullptr);
+          this->ExternalLibRefs.emplace(libItem->Value.Value, buildFile);
+        } else {
+          buildFile = it->second;
+        }
+      } else {
+        // Add this library item back to a regular linker flag list
+        for (const auto& conf : configItemMap) {
+          addToLinkerArguments(conf.first, libItem);
+        }
+        continue;
+      }
     } else {
-      buildFile = it->second;
+      // Add the target output file as a build reference for other targets
+      // to link against
+      auto* fileRefObject = libTarget->GetObject("productReference");
+      if (!fileRefObject) {
+        // Add this library item back to a regular linker flag list
+        for (const auto& conf : configItemMap) {
+          addToLinkerArguments(conf.first, libItem);
+        }
+        continue;
+      }
+      auto it = FileRefToBuildFileMap.find(fileRefObject);
+      if (it == FileRefToBuildFileMap.end()) {
+        buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile);
+        buildFile->AddAttribute("fileRef", fileRefObject);
+        FileRefToBuildFileMap[fileRefObject] = buildFile;
+      } else {
+        buildFile = it->second;
+      }
     }
     // Add this reference to current target
     auto* buildPhases = target->GetObject("buildPhases");
@@ -3164,6 +3263,7 @@
   this->ClearXCodeObjects();
   this->RootObject = nullptr;
   this->MainGroupChildren = nullptr;
+  this->FrameworkGroup = nullptr;
   cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP);
   group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO"));
   cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
@@ -3198,6 +3298,15 @@
   productGroup->AddAttribute("children", productGroupChildren);
   this->MainGroupChildren->AddObject(productGroup);
 
+  this->FrameworkGroup = this->CreateObject(cmXCodeObject::PBXGroup);
+  this->FrameworkGroup->AddAttribute("name", this->CreateString("Frameworks"));
+  this->FrameworkGroup->AddAttribute("sourceTree",
+                                     this->CreateString("<group>"));
+  cmXCodeObject* frameworkGroupChildren =
+    this->CreateObject(cmXCodeObject::OBJECT_LIST);
+  this->FrameworkGroup->AddAttribute("children", frameworkGroupChildren);
+  this->MainGroupChildren->AddObject(this->FrameworkGroup);
+
   this->RootObject = this->CreateObject(cmXCodeObject::PBXProject);
   this->RootObject->SetComment("Project object");
 
@@ -3274,6 +3383,14 @@
   if (archs.empty()) {
     // Tell Xcode to use NATIVE_ARCH instead of ARCHS.
     buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("YES"));
+    // When targeting macOS, use only the host architecture.
+    if (this->SystemName == "Darwin"_s &&
+        (!sysroot || !*sysroot ||
+         cmSystemTools::LowerCase(sysroot).find("macos") !=
+           std::string::npos)) {
+      buildSettings->AddAttribute("ARCHS",
+                                  this->CreateString("$(NATIVE_ARCH_ACTUAL)"));
+    }
   } else {
     // Tell Xcode to use ARCHS (ONLY_ACTIVE_ARCH defaults to NO).
     buildSettings->AddAttribute("ARCHS", this->CreateString(archs));
@@ -3305,6 +3422,12 @@
   std::string symroot = cmStrCat(root->GetCurrentBinaryDirectory(), "/build");
   buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot));
 
+  // Inside a try_compile project, do not require signing on any platform.
+  if (this->CMakeInstance->GetIsInTryCompile()) {
+    buildSettings->AddAttribute("CODE_SIGNING_ALLOWED",
+                                this->CreateString("NO"));
+  }
+
   for (auto& config : configs) {
     cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings);
 
@@ -3373,7 +3496,8 @@
   }
 
   if (this->Architectures.empty()) {
-    // With no ARCHS we use ONLY_ACTIVE_ARCH.
+    // With no ARCHS we use ONLY_ACTIVE_ARCH and possibly a
+    // platform-specific default ARCHS placeholder value.
     // Look up the arch that Xcode chooses in this case.
     if (const char* arch = mf->GetDefinition("CMAKE_XCODE_ARCHS")) {
       this->ObjectDirArchDefault = arch;
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index 11b9312..7018de7 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -109,6 +109,7 @@
 
   bool ShouldStripResourcePath(cmMakefile*) const override;
 
+  bool SetSystemName(std::string const& s, cmMakefile* mf) override;
   bool SetGeneratorToolset(std::string const& ts, bool build,
                            cmMakefile* mf) override;
   void AppendFlag(std::string& flags, std::string const& flag) const;
@@ -203,10 +204,10 @@
                                                   cmGeneratorTarget* target,
                                                   const std::string& lang,
                                                   cmSourceFile* sf);
-  cmXCodeObject* CreateXCodeSourceFileFromPath(const std::string& fullpath,
-                                               cmGeneratorTarget* target,
-                                               const std::string& lang,
-                                               cmSourceFile* sf);
+  cmXCodeObject* CreateXCodeBuildFileFromPath(const std::string& fullpath,
+                                              cmGeneratorTarget* target,
+                                              const std::string& lang,
+                                              cmSourceFile* sf);
   cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf,
                                           cmGeneratorTarget* target);
   cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen, cmSourceFile* sf,
@@ -281,6 +282,7 @@
   std::string PostBuildMakeTarget(std::string const& tName,
                                   std::string const& configName);
   cmXCodeObject* MainGroupChildren;
+  cmXCodeObject* FrameworkGroup;
   cmMakefile* CurrentMakefile;
   cmLocalGenerator* CurrentLocalGenerator;
   std::vector<std::string> CurrentConfigurationTypes;
@@ -294,11 +296,13 @@
   std::map<std::string, cmXCodeObject*> GroupNameMap;
   std::map<std::string, cmXCodeObject*> TargetGroup;
   std::map<std::string, cmXCodeObject*> FileRefs;
+  std::map<std::string, cmXCodeObject*> ExternalLibRefs;
   std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap;
   std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap;
   std::vector<std::string> Architectures;
   std::string ObjectDirArchDefault;
   std::string ObjectDirArch;
+  std::string SystemName;
   std::string GeneratorToolset;
   std::map<cmGeneratorTarget const*, size_t> TargetOrderIndex;
   std::vector<std::string> EnabledLangs;
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 0fcda4e..c23156d 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -67,6 +67,36 @@
       return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN;
   }
 }
+
+struct DependeesDir
+{
+  template <typename T>
+  static const cmLinkItem& src(const T& con)
+  {
+    return con.src;
+  }
+
+  template <typename T>
+  static const cmLinkItem& dst(const T& con)
+  {
+    return con.dst;
+  }
+};
+
+struct DependersDir
+{
+  template <typename T>
+  static const cmLinkItem& src(const T& con)
+  {
+    return con.dst;
+  }
+
+  template <typename T>
+  static const cmLinkItem& dst(const T& con)
+  {
+    return con.src;
+  }
+};
 }
 
 cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName,
@@ -173,18 +203,16 @@
     return;
   }
 
+  // write global data directly
   this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType);
 
   if (this->GeneratePerTarget) {
-    auto fileStream = PerTargetFileStreams[depender.AsStr()].get();
-    this->WriteNode(*fileStream, dependee);
-    this->WriteConnection(*fileStream, depender, dependee, scopeType);
+    PerTargetConnections[depender].emplace_back(depender, dependee, scopeType);
   }
 
   if (this->GenerateDependers) {
-    auto fileStream = TargetDependersFileStreams[dependee.AsStr()].get();
-    this->WriteNode(*fileStream, depender);
-    this->WriteConnection(*fileStream, depender, dependee, scopeType);
+    TargetDependersConnections[dependee].emplace_back(dependee, depender,
+                                                      scopeType);
   }
 }
 
@@ -288,10 +316,86 @@
     }
   }
 
+  // write global data and collect all connection data for per target graphs
   for (auto const gt : sortedGeneratorTargets) {
     auto item = cmLinkItem(gt, false, gt->GetBacktrace());
     this->VisitItem(item);
   }
+
+  if (this->GeneratePerTarget) {
+    WritePerTargetConnections<DependeesDir>(PerTargetConnections,
+                                            PerTargetFileStreams);
+  }
+
+  if (this->GenerateDependers) {
+    WritePerTargetConnections<DependersDir>(TargetDependersConnections,
+                                            TargetDependersFileStreams);
+  }
+}
+
+void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap,
+                                          const cmLinkItem& rootItem,
+                                          Connections& extendedCons,
+                                          std::set<cmLinkItem>& visitedItems)
+{
+  // some "targets" are not in map, e.g. linker flags as -lm or
+  // targets without dependency.
+  // in both cases we are finished with traversing the graph
+  if (connectionMap.find(rootItem) == connectionMap.cend()) {
+    return;
+  }
+
+  const Connections& origCons = connectionMap.at(rootItem);
+
+  for (const Connection& con : origCons) {
+    extendedCons.emplace_back(con);
+    const cmLinkItem& dstItem = con.dst;
+    bool const visited = visitedItems.find(dstItem) != visitedItems.cend();
+    if (!visited) {
+      visitedItems.insert(dstItem);
+      FindAllConnections(connectionMap, dstItem, extendedCons, visitedItems);
+    }
+  }
+}
+
+void cmGraphVizWriter::FindAllConnections(const ConnectionsMap& connectionMap,
+                                          const cmLinkItem& rootItem,
+                                          Connections& extendedCons)
+{
+  std::set<cmLinkItem> visitedItems = { rootItem };
+  FindAllConnections(connectionMap, rootItem, extendedCons, visitedItems);
+}
+
+template <typename DirFunc>
+void cmGraphVizWriter::WritePerTargetConnections(
+  const ConnectionsMap& connections, const FileStreamMap& streams)
+{
+  // the per target connections must be extended by indirect dependencies
+  ConnectionsMap extendedConnections;
+  for (auto const& conPerTarget : connections) {
+    const cmLinkItem& rootItem = conPerTarget.first;
+    Connections& extendedCons = extendedConnections[conPerTarget.first];
+    FindAllConnections(connections, rootItem, extendedCons);
+  }
+
+  for (auto const& conPerTarget : extendedConnections) {
+    const cmLinkItem& rootItem = conPerTarget.first;
+
+    // some of the nodes are excluded completely and are not written
+    if (this->ItemExcluded(rootItem)) {
+      continue;
+    }
+
+    const Connections& cons = conPerTarget.second;
+    auto fileStream = streams.at(rootItem.AsStr()).get();
+
+    for (const Connection& con : cons) {
+      const cmLinkItem& src = DirFunc::src(con);
+      const cmLinkItem& dst = DirFunc::dst(con);
+      this->WriteNode(*fileStream, con.dst);
+      this->WriteConnection(*fileStream, src, dst, con.scopeType);
+    }
+  }
 }
 
 void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& fs,
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index 578660d..9766068 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -7,16 +7,18 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "cmsys/RegularExpression.hxx"
 
 #include "cmGeneratedFileStream.h"
+#include "cmLinkItem.h"
 #include "cmLinkItemGraphVisitor.h"
 #include "cmStateTypes.h"
 
-class cmLinkItem;
 class cmGlobalGenerator;
 
 /** This class implements writing files for graphviz (dot) for graphs
@@ -47,6 +49,22 @@
   using FileStreamMap =
     std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>;
 
+  struct Connection
+  {
+    Connection(cmLinkItem s, cmLinkItem d, std::string scope)
+      : src(std::move(s))
+      , dst(std::move(d))
+      , scopeType(std::move(scope))
+    {
+    }
+
+    cmLinkItem src;
+    cmLinkItem dst;
+    std::string scopeType;
+  };
+  using Connections = std::vector<Connection>;
+  using ConnectionsMap = std::map<cmLinkItem, Connections>;
+
   void VisitLink(cmLinkItem const& depender, cmLinkItem const& dependee,
                  bool isDirectLink, std::string const& scopeType = "");
 
@@ -66,6 +84,19 @@
                        cmLinkItem const& dependeeTargetName,
                        std::string const& edgeStyle);
 
+  void FindAllConnections(const ConnectionsMap& connectionMap,
+                          const cmLinkItem& rootItem,
+                          Connections& extendedCons,
+                          std::set<cmLinkItem>& visitedItems);
+
+  void FindAllConnections(const ConnectionsMap& connectionMap,
+                          const cmLinkItem& rootItem,
+                          Connections& extendedCons);
+
+  template <typename DirFunc>
+  void WritePerTargetConnections(const ConnectionsMap& connections,
+                                 const FileStreamMap& streams);
+
   bool ItemExcluded(cmLinkItem const& item);
   bool ItemNameFilteredOut(std::string const& itemName);
   bool TargetTypeEnabled(cmStateEnums::TargetType targetType) const;
@@ -83,6 +114,9 @@
   FileStreamMap PerTargetFileStreams;
   FileStreamMap TargetDependersFileStreams;
 
+  ConnectionsMap PerTargetConnections;
+  ConnectionsMap TargetDependersConnections;
+
   std::string GraphName;
   std::string GraphHeader;
   std::string GraphNodePrefix;
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 178af73..ddd6c22 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -680,7 +680,7 @@
 
     if (createInstallGeneratorsForTargetFileSets && !namelinkOnly) {
       cmProp files = target.GetProperty("PRIVATE_HEADER");
-      if (files && !files->empty()) {
+      if (cmNonempty(files)) {
         std::vector<std::string> relFiles = cmExpandedList(*files);
         std::vector<std::string> absFiles;
         if (!helper.MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles)) {
@@ -702,7 +702,7 @@
       }
 
       files = target.GetProperty("PUBLIC_HEADER");
-      if (files && !files->empty()) {
+      if (cmNonempty(files)) {
         std::vector<std::string> relFiles = cmExpandedList(*files);
         std::vector<std::string> absFiles;
         if (!helper.MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles)) {
@@ -724,7 +724,7 @@
       }
 
       files = target.GetProperty("RESOURCE");
-      if (files && !files->empty()) {
+      if (cmNonempty(files)) {
         std::vector<std::string> relFiles = cmExpandedList(*files);
         std::vector<std::string> absFiles;
         if (!helper.MakeFilesFullPath("RESOURCE", relFiles, absFiles)) {
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
index c50a786..5739fec 100644
--- a/Source/cmLinkLineDeviceComputer.cxx
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -191,21 +191,18 @@
     target.GetLinkClosure(config);
 
   if (cm::contains(closure->Languages, "CUDA")) {
-    if (cmProp separableCompilation =
-          target.GetProperty("CUDA_SEPARABLE_COMPILATION")) {
-      if (cmIsOn(*separableCompilation)) {
-        bool doDeviceLinking = false;
-        switch (target.GetType()) {
-          case cmStateEnums::SHARED_LIBRARY:
-          case cmStateEnums::MODULE_LIBRARY:
-          case cmStateEnums::EXECUTABLE:
-            doDeviceLinking = true;
-            break;
-          default:
-            break;
-        }
-        return doDeviceLinking;
+    if (cmIsOn(target.GetProperty("CUDA_SEPARABLE_COMPILATION"))) {
+      bool doDeviceLinking = false;
+      switch (target.GetType()) {
+        case cmStateEnums::SHARED_LIBRARY:
+        case cmStateEnums::MODULE_LIBRARY:
+        case cmStateEnums::EXECUTABLE:
+          doDeviceLinking = true;
+          break;
+        default:
+          break;
       }
+      return doDeviceLinking;
     }
 
     cmComputeLinkInformation* pcli = target.GetLinkInformation(config);
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 489065b..fe0d0a7 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -130,7 +130,7 @@
     this->LinkerSysroot = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
   }
 
-  if (std::string const* appleArchSysroots =
+  if (cmProp appleArchSysroots =
         this->Makefile->GetDef("CMAKE_APPLE_ARCH_SYSROOTS")) {
     std::string const& appleArchs =
       this->Makefile->GetSafeDefinition("CMAKE_OSX_ARCHITECTURES");
@@ -1543,9 +1543,8 @@
                                   frameworkPath, linkPath);
       }
 
-      if (cmIsOn(this->Makefile->GetDefinition("BUILD_SHARED_LIBS"))) {
-        std::string sFlagVar = std::string("CMAKE_SHARED_BUILD_") +
-          linkLanguage + std::string("_FLAGS");
+      if (this->Makefile->IsOn("BUILD_SHARED_LIBS")) {
+        std::string sFlagVar = "CMAKE_SHARED_BUILD_" + linkLanguage + "_FLAGS";
         exeFlags += this->Makefile->GetSafeDefinition(sFlagVar);
         exeFlags += " ";
       }
@@ -1972,7 +1971,7 @@
   // of a default selection whether or not it is overridden by a property.
   cmProp msvcRuntimeLibraryDefault =
     this->Makefile->GetDef("CMAKE_MSVC_RUNTIME_LIBRARY_DEFAULT");
-  if (msvcRuntimeLibraryDefault && !msvcRuntimeLibraryDefault->empty()) {
+  if (cmNonempty(msvcRuntimeLibraryDefault)) {
     cmProp msvcRuntimeLibraryValue =
       target->GetProperty("MSVC_RUNTIME_LIBRARY");
     if (!msvcRuntimeLibraryValue) {
@@ -2157,153 +2156,18 @@
   std::string& flags, cmGeneratorTarget const* target, const std::string& lang,
   const std::string& config)
 {
-  if (lang.empty()) {
-    return;
-  }
-  const char* defaultStd =
-    this->Makefile->GetDefinition("CMAKE_" + lang + "_STANDARD_DEFAULT");
-  if (!defaultStd || !*defaultStd) {
-    // This compiler has no notion of language standard levels.
-    return;
-  }
-  bool ext = true;
-  if (cmProp extPropValue = target->GetLanguageExtensions(lang)) {
-    if (cmIsOff(*extPropValue)) {
-      ext = false;
-    }
-  }
-  cmProp standardProp = target->GetLanguageStandard(lang, config);
-  if (!standardProp) {
-    if (ext) {
-      // No language standard is specified and extensions are not disabled.
-      // Check if this compiler needs a flag to enable extensions.
-      std::string const option_flag =
-        "CMAKE_" + lang + "_EXTENSION_COMPILE_OPTION";
-      if (const char* opt =
-            target->Target->GetMakefile()->GetDefinition(option_flag)) {
-        std::vector<std::string> optVec = cmExpandedList(opt);
-        for (std::string const& i : optVec) {
-          this->AppendFlagEscape(flags, i);
-        }
-      }
-    }
-    return;
-  }
+  cmStandardLevelResolver standardResolver(this->Makefile);
 
-  std::string const type = ext ? "EXTENSION" : "STANDARD";
-
-  if (target->GetLanguageStandardRequired(lang)) {
-    std::string option_flag =
-      "CMAKE_" + lang + *standardProp + "_" + type + "_COMPILE_OPTION";
-
-    const char* opt =
-      target->Target->GetMakefile()->GetDefinition(option_flag);
-    if (!opt) {
-      std::ostringstream e;
-      e << "Target \"" << target->GetName()
-        << "\" requires the language "
-           "dialect \""
-        << lang << *standardProp << "\" "
-        << (ext ? "(with compiler extensions)" : "")
-        << ", but CMake "
-           "does not know the compile flags to use to enable it.";
-      this->IssueMessage(MessageType::FATAL_ERROR, e.str());
-    } else {
+  std::string const& optionFlagDef =
+    standardResolver.GetCompileOptionDef(target, lang, config);
+  if (!optionFlagDef.empty()) {
+    auto opt = target->Target->GetMakefile()->GetDefinition(optionFlagDef);
+    if (opt) {
       std::vector<std::string> optVec = cmExpandedList(opt);
       for (std::string const& i : optVec) {
         this->AppendFlagEscape(flags, i);
       }
     }
-    return;
-  }
-
-  static std::map<std::string, std::vector<std::string>> langStdMap;
-  if (langStdMap.empty()) {
-    // Maintain sorted order, most recent first.
-    langStdMap["CXX"].emplace_back("20");
-    langStdMap["CXX"].emplace_back("17");
-    langStdMap["CXX"].emplace_back("14");
-    langStdMap["CXX"].emplace_back("11");
-    langStdMap["CXX"].emplace_back("98");
-
-    langStdMap["OBJCXX"].emplace_back("20");
-    langStdMap["OBJCXX"].emplace_back("17");
-    langStdMap["OBJCXX"].emplace_back("14");
-    langStdMap["OBJCXX"].emplace_back("11");
-    langStdMap["OBJCXX"].emplace_back("98");
-
-    langStdMap["C"].emplace_back("11");
-    langStdMap["C"].emplace_back("99");
-    langStdMap["C"].emplace_back("90");
-
-    langStdMap["OBJC"].emplace_back("11");
-    langStdMap["OBJC"].emplace_back("99");
-    langStdMap["OBJC"].emplace_back("90");
-
-    langStdMap["CUDA"].emplace_back("20");
-    langStdMap["CUDA"].emplace_back("17");
-    langStdMap["CUDA"].emplace_back("14");
-    langStdMap["CUDA"].emplace_back("11");
-    langStdMap["CUDA"].emplace_back("03");
-  }
-
-  std::string standard(*standardProp);
-  if (lang == "CUDA" && standard == "98") {
-    standard = "03";
-  }
-  std::vector<std::string>& stds = langStdMap[lang];
-
-  auto stdIt = std::find(stds.begin(), stds.end(), standard);
-  if (stdIt == stds.end()) {
-
-    std::string e =
-      lang + "_STANDARD is set to invalid value '" + standard + "'";
-    this->GetGlobalGenerator()->GetCMakeInstance()->IssueMessage(
-      MessageType::FATAL_ERROR, e, target->GetBacktrace());
-    return;
-  }
-
-  auto defaultStdIt = std::find(stds.begin(), stds.end(), defaultStd);
-  if (defaultStdIt == stds.end()) {
-    std::string e = "CMAKE_" + lang +
-      "_STANDARD_DEFAULT is set to invalid value '" + std::string(defaultStd) +
-      "'";
-    this->IssueMessage(MessageType::INTERNAL_ERROR, e);
-    return;
-  }
-
-  // If the standard requested is older than the compiler's default
-  // then we need to use a flag to change it.  The comparison is
-  // greater-or-equal because the standards are stored in backward
-  // chronological order.
-  if (stdIt >= defaultStdIt) {
-    std::string option_flag =
-      "CMAKE_" + lang + *stdIt + "_" + type + "_COMPILE_OPTION";
-
-    std::string const& opt =
-      target->Target->GetMakefile()->GetRequiredDefinition(option_flag);
-    std::vector<std::string> optVec = cmExpandedList(opt);
-    for (std::string const& i : optVec) {
-      this->AppendFlagEscape(flags, i);
-    }
-    return;
-  }
-
-  // The standard requested is at least as new as the compiler's default,
-  // and the standard request is not required.  Decay to the newest standard
-  // for which a flag is defined.
-  for (; stdIt < defaultStdIt; ++stdIt) {
-    std::string option_flag =
-      cmStrCat("CMAKE_", lang, *stdIt, "_", type, "_COMPILE_OPTION");
-
-    if (const char* opt =
-          target->Target->GetMakefile()->GetDefinition(option_flag)) {
-      std::vector<std::string> optVec = cmExpandedList(opt);
-      for (std::string const& i : optVec) {
-        this->AppendFlagEscape(flags, i);
-      }
-      return;
-    }
   }
 }
 
@@ -3253,8 +3117,8 @@
   }
 }
 
-const char* cmLocalGenerator::GetFeature(const std::string& feature,
-                                         const std::string& config)
+cmProp cmLocalGenerator::GetFeature(const std::string& feature,
+                                    const std::string& config)
 {
   std::string featureName = feature;
   // TODO: Define accumulation policy for features (prepend, append,
@@ -3266,7 +3130,7 @@
   cmStateSnapshot snp = this->StateSnapshot;
   while (snp.IsValid()) {
     if (cmProp value = snp.GetDirectory().GetProperty(featureName)) {
-      return value->c_str();
+      return value;
     }
     snp = snp.GetBuildsystemDirectoryParent();
   }
@@ -3807,8 +3671,7 @@
 {
   // Find the Info.plist template.
   cmProp in = target->GetProperty("MACOSX_BUNDLE_INFO_PLIST");
-  std::string inFile =
-    (in && !in->empty()) ? *in : "MacOSXBundleInfo.plist.in";
+  std::string inFile = cmNonempty(in) ? *in : "MacOSXBundleInfo.plist.in";
   if (!cmSystemTools::FileIsFullPath(inFile)) {
     std::string inMod = this->Makefile->GetModulesFile(inFile);
     if (!inMod.empty()) {
@@ -3847,8 +3710,7 @@
 {
   // Find the Info.plist template.
   cmProp in = target->GetProperty("MACOSX_FRAMEWORK_INFO_PLIST");
-  std::string inFile =
-    (in && !in->empty()) ? *in : "MacOSXFrameworkInfo.plist.in";
+  std::string inFile = cmNonempty(in) ? *in : "MacOSXFrameworkInfo.plist.in";
   if (!cmSystemTools::FileIsFullPath(inFile)) {
     std::string inMod = this->Makefile->GetModulesFile(inFile);
     if (!inMod.empty()) {
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index f4781d6..0c51a65 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -20,6 +20,7 @@
 #include "cmMessageType.h"
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
+#include "cmProperty.h"
 #include "cmStateSnapshot.h"
 
 class cmComputeLinkInformation;
@@ -209,8 +210,7 @@
   void AppendFeatureOptions(std::string& flags, const std::string& lang,
                             const char* feature);
 
-  const char* GetFeature(const std::string& feature,
-                         const std::string& config);
+  cmProp GetFeature(const std::string& feature, const std::string& config);
 
   /** \brief Get absolute path to dependency \a name
    *
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index 87e8aa4..aee7f45 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -668,7 +668,7 @@
 {
   cmProp property_value = this->Makefile->GetProperty("RULE_LAUNCH_CUSTOM");
 
-  if (!property_value || property_value->empty()) {
+  if (!cmNonempty(property_value)) {
     return std::string();
   }
 
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index de1461a..86a888a 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -950,7 +950,7 @@
       std::string launcher;
       // Short-circuit if there is no launcher.
       const char* val = this->GetRuleLauncher(target, "RULE_LAUNCH_CUSTOM");
-      if (val && *val) {
+      if (cmNonempty(val)) {
         // Expand rule variables referenced in the given launcher command.
         cmRulePlaceholderExpander::RuleVariables vars;
         vars.CMTargetName = target->GetName().c_str();
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 4b595a6..aca40fa 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -1462,6 +1462,9 @@
   // Imported targets.
   this->ImportedTargets = parent->ImportedTargets;
 
+  // Non-global Alias targets.
+  this->AliasTargets = parent->AliasTargets;
+
   // Recursion depth.
   this->RecursionDepth = parent->RecursionDepth;
 }
@@ -2518,8 +2521,7 @@
 
 bool cmMakefile::IsOn(const std::string& name) const
 {
-  const char* value = this->GetDefinition(name);
-  return cmIsOn(value);
+  return cmIsOn(this->GetDef(name));
 }
 
 bool cmMakefile::IsSet(const std::string& name) const
@@ -4113,8 +4115,7 @@
 
 bool cmMakefile::GetPropertyAsBool(const std::string& prop) const
 {
-  cmProp p = this->GetProperty(prop);
-  return p && cmIsOn(*p);
+  return cmIsOn(this->GetProperty(prop));
 }
 
 std::vector<std::string> cmMakefile::GetPropertyKeys() const
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 446f225..bc288ac 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -218,7 +218,7 @@
 
     const char* val = this->LocalGenerator->GetRuleLauncher(
       this->GeneratorTarget, "RULE_LAUNCH_LINK");
-    if (val && *val) {
+    if (cmNonempty(val)) {
       launcher = cmStrCat(val, ' ');
     }
 
@@ -583,7 +583,7 @@
 
     const char* val = this->LocalGenerator->GetRuleLauncher(
       this->GeneratorTarget, "RULE_LAUNCH_LINK");
-    if (val && *val) {
+    if (cmNonempty(val)) {
       launcher = cmStrCat(val, ' ');
     }
 
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 5809b4a..1c25fc4 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -356,7 +356,7 @@
     std::string launcher;
     const char* val = this->LocalGenerator->GetRuleLauncher(
       this->GeneratorTarget, "RULE_LAUNCH_LINK");
-    if (val && *val) {
+    if (cmNonempty(val)) {
       launcher = cmStrCat(val, ' ');
     }
 
@@ -809,7 +809,7 @@
     std::string launcher;
     const char* val = this->LocalGenerator->GetRuleLauncher(
       this->GeneratorTarget, "RULE_LAUNCH_LINK");
-    if (val && *val) {
+    if (cmNonempty(val)) {
       launcher = cmStrCat(val, ' ');
     }
 
diff --git a/Source/cmMakefileProfilingData.cxx b/Source/cmMakefileProfilingData.cxx
index e0150dc..29fd440 100644
--- a/Source/cmMakefileProfilingData.cxx
+++ b/Source/cmMakefileProfilingData.cxx
@@ -58,7 +58,7 @@
     cmsys::SystemInformation info;
     Json::Value v;
     v["ph"] = "B";
-    v["name"] = lff.Name.Original;
+    v["name"] = lff.Name.Lower;
     v["cat"] = "cmake";
     v["ts"] = Json::Value::UInt64(
       std::chrono::duration_cast<std::chrono::microseconds>(
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 6887569..286a3dc 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -197,8 +197,7 @@
   }
 
   // add custom commands to the clean rules?
-  cmProp clean_no_custom = this->Makefile->GetProperty("CLEAN_NO_CUSTOM");
-  bool clean = clean_no_custom ? cmIsOff(*clean_no_custom) : true;
+  bool clean = cmIsOff(this->Makefile->GetProperty("CLEAN_NO_CUSTOM"));
 
   // First generate the object rule files.  Save a list of all object
   // files for this target.
@@ -807,7 +806,7 @@
          lang == "OBJC" || lang == "OBJCXX")) {
       std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER";
       cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
-      if (clauncher && !clauncher->empty()) {
+      if (cmNonempty(clauncher)) {
         compilerLauncher = *clauncher;
       }
     }
@@ -822,8 +821,8 @@
       cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
       std::string const cppcheck_prop = lang + "_CPPCHECK";
       cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
-      if ((iwyu && !iwyu->empty()) || (tidy && !tidy->empty()) ||
-          (cpplint && !cpplint->empty()) || (cppcheck && !cppcheck->empty())) {
+      if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
+          cmNonempty(cppcheck)) {
         std::string run_iwyu = "$(CMAKE_COMMAND) -E __run_co_compile";
         if (!compilerLauncher.empty()) {
           // In __run_co_compile case the launcher command is supplied
@@ -832,11 +831,11 @@
           run_iwyu += this->LocalGenerator->EscapeForShell(compilerLauncher);
           compilerLauncher.clear();
         }
-        if (iwyu && !iwyu->empty()) {
+        if (cmNonempty(iwyu)) {
           run_iwyu += " --iwyu=";
           run_iwyu += this->LocalGenerator->EscapeForShell(*iwyu);
         }
-        if (tidy && !tidy->empty()) {
+        if (cmNonempty(tidy)) {
           run_iwyu += " --tidy=";
           const char* driverMode = this->Makefile->GetDefinition(
             "CMAKE_" + lang + "_CLANG_TIDY_DRIVER_MODE");
@@ -846,16 +845,16 @@
           run_iwyu += this->LocalGenerator->EscapeForShell(
             cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode));
         }
-        if (cpplint && !cpplint->empty()) {
+        if (cmNonempty(cpplint)) {
           run_iwyu += " --cpplint=";
           run_iwyu += this->LocalGenerator->EscapeForShell(*cpplint);
         }
-        if (cppcheck && !cppcheck->empty()) {
+        if (cmNonempty(cppcheck)) {
           run_iwyu += " --cppcheck=";
           run_iwyu += this->LocalGenerator->EscapeForShell(*cppcheck);
         }
-        if ((tidy && !tidy->empty()) || (cpplint && !cpplint->empty()) ||
-            (cppcheck && !cppcheck->empty())) {
+        if (cmNonempty(tidy) || (cmNonempty(cpplint)) ||
+            (cmNonempty(cppcheck))) {
           run_iwyu += " --source=";
           run_iwyu += sourceFile;
         }
@@ -882,7 +881,7 @@
     {
       const char* val = this->LocalGenerator->GetRuleLauncher(
         this->GeneratorTarget, "RULE_LAUNCH_COMPILE");
-      if (val && *val) {
+      if (cmNonempty(val)) {
         launcher = cmStrCat(val, ' ');
       }
     }
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index b92548f..de68371 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -239,7 +239,7 @@
     std::string launcher;
     const char* val = this->GetLocalGenerator()->GetRuleLauncher(
       this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
-    if (val && *val) {
+    if (cmNonempty(val)) {
       launcher = cmStrCat(val, ' ');
     }
 
@@ -376,7 +376,7 @@
     std::string launcher;
     const char* val = this->GetLocalGenerator()->GetRuleLauncher(
       this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
-    if (val && *val) {
+    if (cmNonempty(val)) {
       launcher = cmStrCat(val, ' ');
     }
 
@@ -733,8 +733,13 @@
     static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
     globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule(config));
 
-  build.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") +
-                                           genTarget->GetName() + ".rsp");
+  std::string path = localGen.GetHomeRelativeOutputPath();
+  if (!path.empty()) {
+    path += '/';
+  }
+  build.RspFile = this->ConvertToNinjaPath(
+    cmStrCat(path, "CMakeFiles/", genTarget->GetName(),
+             globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp"));
 
   // Gather order-only dependencies.
   this->GetLocalGenerator()->AppendTargetDepends(
@@ -1154,8 +1159,13 @@
       globalGen->GetRuleCmdLength(linkBuild.Rule);
   }
 
-  linkBuild.RspFile = this->ConvertToNinjaPath(std::string("CMakeFiles/") +
-                                               gt->GetName() + ".rsp");
+  std::string path = localGen.GetHomeRelativeOutputPath();
+  if (!path.empty()) {
+    path += '/';
+  }
+  linkBuild.RspFile = this->ConvertToNinjaPath(
+    cmStrCat(path, "CMakeFiles/", gt->GetName(),
+             globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp"));
 
   // Gather order-only dependencies.
   this->GetLocalGenerator()->AppendTargetDepends(gt, linkBuild.OrderOnlyDeps,
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 53a0cb7..de18536 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -662,7 +662,7 @@
   std::string launcher;
   const char* val = this->GetLocalGenerator()->GetRuleLauncher(
     this->GetGeneratorTarget(), "RULE_LAUNCH_COMPILE");
-  if (val && *val) {
+  if (cmNonempty(val)) {
     launcher = cmStrCat(val, ' ');
   }
 
@@ -813,7 +813,7 @@
        lang == "OBJC" || lang == "OBJCXX")) {
     std::string const clauncher_prop = cmStrCat(lang, "_COMPILER_LAUNCHER");
     cmProp clauncher = this->GeneratorTarget->GetProperty(clauncher_prop);
-    if (clauncher && !clauncher->empty()) {
+    if (cmNonempty(clauncher)) {
       compilerLauncher = *clauncher;
     }
   }
@@ -828,8 +828,8 @@
     cmProp cpplint = this->GeneratorTarget->GetProperty(cpplint_prop);
     std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK");
     cmProp cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop);
-    if ((iwyu && !iwyu->empty()) || (tidy && !tidy->empty()) ||
-        (cpplint && !cpplint->empty()) || (cppcheck && !cppcheck->empty())) {
+    if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) ||
+        cmNonempty(cppcheck)) {
       std::string run_iwyu = cmStrCat(cmakeCmd, " -E __run_co_compile");
       if (!compilerLauncher.empty()) {
         // In __run_co_compile case the launcher command is supplied
@@ -839,11 +839,11 @@
                    this->LocalGenerator->EscapeForShell(compilerLauncher));
         compilerLauncher.clear();
       }
-      if (iwyu && !iwyu->empty()) {
+      if (cmNonempty(iwyu)) {
         run_iwyu += cmStrCat(" --iwyu=",
                              this->GetLocalGenerator()->EscapeForShell(*iwyu));
       }
-      if (tidy && !tidy->empty()) {
+      if (cmNonempty(tidy)) {
         run_iwyu += " --tidy=";
         const char* driverMode = this->Makefile->GetDefinition(
           cmStrCat("CMAKE_", lang, "_CLANG_TIDY_DRIVER_MODE"));
@@ -853,17 +853,16 @@
         run_iwyu += this->GetLocalGenerator()->EscapeForShell(
           cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode));
       }
-      if (cpplint && !cpplint->empty()) {
+      if (cmNonempty(cpplint)) {
         run_iwyu += cmStrCat(
           " --cpplint=", this->GetLocalGenerator()->EscapeForShell(*cpplint));
       }
-      if (cppcheck && !cppcheck->empty()) {
+      if (cmNonempty(cppcheck)) {
         run_iwyu +=
           cmStrCat(" --cppcheck=",
                    this->GetLocalGenerator()->EscapeForShell(*cppcheck));
       }
-      if ((tidy && !tidy->empty()) || (cpplint && !cpplint->empty()) ||
-          (cppcheck && !cppcheck->empty())) {
+      if (cmNonempty(tidy) || cmNonempty(cpplint) || cmNonempty(cppcheck)) {
         run_iwyu += " --source=$in";
       }
       run_iwyu += " -- ";
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 3d4f5d7..fac2bbf 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -50,7 +50,7 @@
     {
       cmMakefile* makefile = localGen->GetMakefile();
       // Detect global autogen target name
-      if (cmIsOn(makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET"))) {
+      if (makefile->IsOn("CMAKE_GLOBAL_AUTOGEN_TARGET")) {
         std::string targetName =
           makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME");
         if (targetName.empty()) {
@@ -61,7 +61,7 @@
       }
 
       // Detect global autorcc target name
-      if (cmIsOn(makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET"))) {
+      if (makefile->IsOn("CMAKE_GLOBAL_AUTORCC_TARGET")) {
         std::string targetName =
           makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME");
         if (targetName.empty()) {
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 7e0bf96..218bd4c 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -489,7 +489,7 @@
 
     if (this->Moc.Enabled) {
       // Path prefix
-      if (cmIsOn(this->GenTarget->GetSafeProperty("AUTOMOC_PATH_PREFIX"))) {
+      if (cmIsOn(this->GenTarget->GetProperty("AUTOMOC_PATH_PREFIX"))) {
         this->Moc.PathPrefix = true;
       }
 
@@ -1610,7 +1610,7 @@
       };
       for (std::string const& prop : props) {
         cmProp propName = this->Makefile->GetState()->GetGlobalProperty(prop);
-        if (propName && !propName->empty()) {
+        if (cmNonempty(propName)) {
           groupName = *propName;
           property = prop;
           break;
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index 51509fd..6ca763b 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -4,6 +4,7 @@
 
 #include <set>
 #include <sstream>
+#include <unordered_set>
 
 #include "cmExecutionStatus.h"
 #include "cmGlobalGenerator.h"
@@ -82,6 +83,8 @@
   std::vector<std::string>& source_file_target_directories,
   std::vector<cmMakefile*>& directory_makefiles)
 {
+  std::unordered_set<cmMakefile*> directory_makefiles_set;
+
   cmMakefile* current_dir_mf = &status.GetMakefile();
   if (!source_file_directories.empty()) {
     for (const std::string& dir_path : source_file_directories) {
@@ -94,7 +97,11 @@
         status.SetError(cmStrCat("given non-existent DIRECTORY ", dir_path));
         return false;
       }
-      directory_makefiles.push_back(dir_mf);
+      if (directory_makefiles_set.find(dir_mf) ==
+          directory_makefiles_set.end()) {
+        directory_makefiles.push_back(dir_mf);
+        directory_makefiles_set.insert(dir_mf);
+      }
     }
   }
 
@@ -110,7 +117,12 @@
       cmMakefile* target_dir_mf =
         status.GetMakefile().GetGlobalGenerator()->FindMakefile(
           *target_source_dir);
-      directory_makefiles.push_back(target_dir_mf);
+
+      if (directory_makefiles_set.find(target_dir_mf) ==
+          directory_makefiles_set.end()) {
+        directory_makefiles.push_back(target_dir_mf);
+        directory_makefiles_set.insert(target_dir_mf);
+      }
     }
   }
 
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 781ddbc..ef44a57 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -380,8 +380,7 @@
 
 bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
 {
-  cmProp p = this->GetProperty(prop);
-  return p && cmIsOn(*p);
+  return cmIsOn(this->GetProperty(prop));
 }
 
 void cmSourceFile::SetProperties(cmPropertyMap properties)
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
index 5e30680..0eb869c 100644
--- a/Source/cmStandardLevelResolver.cxx
+++ b/Source/cmStandardLevelResolver.cxx
@@ -7,6 +7,7 @@
 #include <cassert>
 #include <cstddef>
 #include <sstream>
+#include <stdexcept>
 #include <unordered_map>
 #include <utility>
 #include <vector>
@@ -45,10 +46,126 @@
 
 struct StanardLevelComputer
 {
-  explicit StanardLevelComputer(std::string lang, std::vector<int> levels)
+  explicit StanardLevelComputer(std::string lang, std::vector<int> levels,
+                                std::vector<std::string> levelsStr)
     : Language(std::move(lang))
     , Levels(std::move(levels))
+    , LevelsAsStrings(std::move(levelsStr))
   {
+    assert(levels.size() == levelsStr.size());
+  }
+
+  std::string GetCompileOptionDef(cmMakefile* makefile,
+                                  cmGeneratorTarget const* target,
+                                  std::string const& config) const
+  {
+
+    const auto& stds = this->Levels;
+    const auto& stdsStrings = this->LevelsAsStrings;
+
+    const char* defaultStd = makefile->GetDefinition(
+      cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
+    if (!defaultStd || !*defaultStd) {
+      // this compiler has no notion of language standard levels
+      return std::string{};
+    }
+
+    bool ext = true;
+    if (cmProp extPropValue = target->GetLanguageExtensions(this->Language)) {
+      if (cmIsOff(*extPropValue)) {
+        ext = false;
+      }
+    }
+
+    cmProp standardProp = target->GetLanguageStandard(this->Language, config);
+    if (!standardProp) {
+      if (ext) {
+        // No language standard is specified and extensions are not disabled.
+        // Check if this compiler needs a flag to enable extensions.
+        return cmStrCat("CMAKE_", this->Language, "_EXTENSION_COMPILE_OPTION");
+      }
+      return std::string{};
+    }
+
+    std::string const type = ext ? "EXTENSION" : "STANDARD";
+
+    if (target->GetLanguageStandardRequired(this->Language)) {
+      std::string option_flag = cmStrCat(
+        "CMAKE_", this->Language, *standardProp, "_", type, "_COMPILE_OPTION");
+
+      const char* opt =
+        target->Target->GetMakefile()->GetDefinition(option_flag);
+      if (!opt) {
+        std::ostringstream e;
+        e << "Target \"" << target->GetName()
+          << "\" requires the language "
+             "dialect \""
+          << this->Language << *standardProp << "\" "
+          << (ext ? "(with compiler extensions)" : "")
+          << ", but CMake "
+             "does not know the compile flags to use to enable it.";
+        makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
+      }
+      return option_flag;
+    }
+
+    std::string standardStr(*standardProp);
+    if (this->Language == "CUDA" && standardStr == "98") {
+      standardStr = "03";
+    }
+
+    int standardValue = -1;
+    int defaultValue = -1;
+    try {
+      standardValue = std::stoi(standardStr);
+      defaultValue = std::stoi(defaultStd);
+    } catch (std::invalid_argument&) {
+      // fall through as we want an error
+      // when we can't find the bad value in the `stds` vector
+    }
+
+    auto stdIt = std::find(cm::cbegin(stds), cm::cend(stds), standardValue);
+    if (stdIt == cm::cend(stds)) {
+      std::string e =
+        cmStrCat(this->Language, "_STANDARD is set to invalid value '",
+                 standardStr, "'");
+      makefile->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
+                                                 target->GetBacktrace());
+      return std::string{};
+    }
+
+    auto defaultStdIt =
+      std::find(cm::cbegin(stds), cm::cend(stds), defaultValue);
+    if (defaultStdIt == cm::cend(stds)) {
+      std::string e = cmStrCat("CMAKE_", this->Language,
+                               "_STANDARD_DEFAULT is set to invalid value '",
+                               defaultStd, "'");
+      makefile->IssueMessage(MessageType::INTERNAL_ERROR, e);
+      return std::string{};
+    }
+
+    // If the standard requested is older than the compiler's default
+    // then we need to use a flag to change it.
+    if (stdIt <= defaultStdIt) {
+      auto offset = std::distance(cm::cbegin(stds), stdIt);
+      return cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type,
+                      "_COMPILE_OPTION");
+    }
+
+    // The standard requested is at least as new as the compiler's default,
+    // and the standard request is not required.  Decay to the newest standard
+    // for which a flag is defined.
+    for (; defaultStdIt < stdIt; --stdIt) {
+      auto offset = std::distance(cm::cbegin(stds), stdIt);
+      std::string option_flag =
+        cmStrCat("CMAKE_", this->Language, stdsStrings[offset], "_", type,
+                 "_COMPILE_OPTION");
+      if (target->Target->GetMakefile()->GetDefinition(option_flag)) {
+        return option_flag;
+      }
+    }
+
+    return std::string{};
   }
 
   bool GetNewRequiredStandard(cmMakefile* makefile,
@@ -70,7 +187,7 @@
     if (existingStandard == nullptr) {
       cmProp defaultStandard = makefile->GetDef(
         cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
-      if (defaultStandard && !defaultStandard->empty()) {
+      if (cmNonempty(defaultStandard)) {
         existingStandard = defaultStandard;
       }
     }
@@ -99,7 +216,7 @@
       // the needed C++ features.
       if (existingLevelIter == cm::cend(this->Levels) ||
           existingLevelIter < this->Levels.begin() + needed.index) {
-        newRequiredStandard = std::to_string(this->Levels[needed.index]);
+        newRequiredStandard = this->LevelsAsStrings[needed.index];
       }
     }
 
@@ -163,8 +280,8 @@
     std::string prefix = cmStrCat("CMAKE_", this->Language);
     StandardNeeded maxLevel = { -1, -1 };
     for (size_t i = 0; i < this->Levels.size(); ++i) {
-      if (const char* prop = makefile->GetDefinition(cmStrCat(
-            prefix, std::to_string(this->Levels[i]), "_COMPILE_FEATURES"))) {
+      if (const char* prop = makefile->GetDefinition(
+            cmStrCat(prefix, this->LevelsAsStrings[i], "_COMPILE_FEATURES"))) {
         std::vector<std::string> props = cmExpandedList(prop);
         if (cm::contains(props, feature)) {
           maxLevel = { static_cast<int>(i), this->Levels[i] };
@@ -185,22 +302,44 @@
 
   std::string Language;
   std::vector<int> Levels;
+  std::vector<std::string> LevelsAsStrings;
 };
 
 std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping =
   {
-    { "C", StanardLevelComputer{ "C", std::vector<int>{ 90, 99, 11 } } },
+    { "C",
+      StanardLevelComputer{ "C", std::vector<int>{ 90, 99, 11 },
+                            std::vector<std::string>{ "90", "99", "11" } } },
     { "CXX",
-      StanardLevelComputer{ "CXX", std::vector<int>{ 98, 11, 14, 17, 20 } } },
+      StanardLevelComputer{
+        "CXX", std::vector<int>{ 98, 11, 14, 17, 20 },
+        std::vector<std::string>{ "98", "11", "14", "17", "20" } } },
     { "CUDA",
-      StanardLevelComputer{ "CUDA", std::vector<int>{ 03, 11, 14, 17, 20 } } },
-    { "OBJC", StanardLevelComputer{ "OBJC", std::vector<int>{ 90, 99, 11 } } },
+      StanardLevelComputer{
+        "CUDA", std::vector<int>{ 03, 11, 14, 17, 20 },
+        std::vector<std::string>{ "03", "11", "14", "17", "20" } } },
+    { "OBJC",
+      StanardLevelComputer{ "OBJC", std::vector<int>{ 90, 99, 11 },
+                            std::vector<std::string>{ "90", "99", "11" } } },
     { "OBJCXX",
-      StanardLevelComputer{ "OBJCXX",
-                            std::vector<int>{ 98, 11, 14, 17, 20 } } },
+      StanardLevelComputer{
+        "OBJCXX", std::vector<int>{ 98, 11, 14, 17, 20 },
+        std::vector<std::string>{ "98", "11", "14", "17", "20" } } },
   };
 }
 
+std::string cmStandardLevelResolver::GetCompileOptionDef(
+  cmGeneratorTarget const* target, std::string const& lang,
+  std::string const& config) const
+{
+  const auto& mapping = StandardComputerMapping.find(lang);
+  if (mapping == cm::cend(StandardComputerMapping)) {
+    return std::string{};
+  }
+
+  return mapping->second.GetCompileOptionDef(this->Makefile, target, config);
+}
+
 bool cmStandardLevelResolver::AddRequiredTargetFeature(
   cmTarget* target, const std::string& feature, std::string* error) const
 {
diff --git a/Source/cmStandardLevelResolver.h b/Source/cmStandardLevelResolver.h
index 193c053..959a5f9 100644
--- a/Source/cmStandardLevelResolver.h
+++ b/Source/cmStandardLevelResolver.h
@@ -20,6 +20,10 @@
   {
   }
 
+  std::string GetCompileOptionDef(cmGeneratorTarget const* target,
+                                  std::string const& lang,
+                                  std::string const& config) const;
+
   bool AddRequiredTargetFeature(cmTarget* target, const std::string& feature,
                                 std::string* error = nullptr) const;
 
diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h
index cc67ac2..e0b2116 100644
--- a/Source/cmStandardLexer.h
+++ b/Source/cmStandardLexer.h
@@ -3,6 +3,10 @@
 #ifndef cmStandardLexer_h
 #define cmStandardLexer_h
 
+#if defined(__linux)
+/* Needed for glibc < 2.12 */
+#  define _XOPEN_SOURCE 600
+#endif
 #if !defined(_WIN32) && !defined(__sun)
 /* POSIX APIs are needed */
 #  define _POSIX_C_SOURCE 200809L
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index 0b6b40f..73f166c 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -623,8 +623,7 @@
 
 bool cmState::GetGlobalPropertyAsBool(const std::string& prop)
 {
-  cmProp p = this->GetGlobalProperty(prop);
-  return p && cmIsOn(*p);
+  return cmIsOn(this->GetGlobalProperty(prop));
 }
 
 void cmState::SetSourceDirectory(std::string const& sourceDirectory)
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index a4fe663..796bb1f 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -648,8 +648,7 @@
 
 bool cmStateDirectory::GetPropertyAsBool(const std::string& prop) const
 {
-  cmProp p = this->GetProperty(prop);
-  return p && cmIsOn(*p);
+  return cmIsOn(this->GetProperty(prop));
 }
 
 std::vector<std::string> cmStateDirectory::GetPropertyKeys() const
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index cfabc3f..bf8e331 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -323,7 +323,7 @@
 #if defined(__CYGWIN__)
   std::string legacy;
   if (cmSystemTools::GetEnv("CMAKE_LEGACY_CYGWIN_WIN32", legacy) &&
-      cmIsOn(legacy.c_str())) {
+      cmIsOn(legacy)) {
     this->SetDefinition("WIN32", "1");
     this->SetDefinition("CMAKE_HOST_WIN32", "1");
   }
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index a5ecca7..4b0090b 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -20,6 +20,20 @@
 /** String range type.  */
 using cmStringRange = cmRange<std::vector<std::string>::const_iterator>;
 
+/** Check for non-empty string.  */
+inline bool cmNonempty(const char* str)
+{
+  return str && *str;
+}
+inline bool cmNonempty(cm::string_view str)
+{
+  return !str.empty();
+}
+inline bool cmNonempty(std::string const* str)
+{
+  return str && !str->empty();
+}
+
 /** Callable string comparison struct.  */
 struct cmStrCmp
 {
@@ -205,10 +219,11 @@
 bool cmIsOn(cm::string_view val);
 inline bool cmIsOn(const char* val)
 {
-  if (!val) {
-    return false;
-  }
-  return cmIsOn(cm::string_view(val));
+  return val && cmIsOn(cm::string_view(val));
+}
+inline bool cmIsOn(std::string const* val)
+{
+  return val && cmIsOn(*val);
 }
 
 /**
@@ -221,10 +236,11 @@
 bool cmIsOff(cm::string_view val);
 inline bool cmIsOff(const char* val)
 {
-  if (!val) {
-    return true;
-  }
-  return cmIsOff(cm::string_view(val));
+  return !val || cmIsOff(cm::string_view(val));
+}
+inline bool cmIsOff(std::string const* val)
+{
+  return !val || cmIsOff(*val);
 }
 
 /** Returns true if string @a str starts with the character @a prefix.  */
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index a4f9083..aec9afa 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -1884,8 +1884,7 @@
 
 bool cmTarget::GetPropertyAsBool(const std::string& prop) const
 {
-  cmProp p = this->GetProperty(prop);
-  return p && cmIsOn(*p);
+  return cmIsOn(this->GetProperty(prop));
 }
 
 cmPropertyMap const& cmTarget::GetProperties() const
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index e10a8e2..7c0ce71 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -102,7 +102,7 @@
 
     // Prepend with the emulator when cross compiling if required.
     cmProp emulator = target->GetProperty("CROSSCOMPILING_EMULATOR");
-    if (emulator != nullptr && !emulator->empty()) {
+    if (cmNonempty(emulator)) {
       std::vector<std::string> emulatorWithArgs = cmExpandedList(*emulator);
       std::string emulatorExe(emulatorWithArgs[0]);
       cmSystemTools::ConvertToUnixSlashes(emulatorExe);
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 5f6b41d..5d9199b 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -1976,7 +1976,7 @@
   }
 
   cmProp toolOverride = sf->GetProperty("VS_TOOL_OVERRIDE");
-  if (toolOverride && !toolOverride->empty()) {
+  if (cmNonempty(toolOverride)) {
     tool = toolOverride->c_str();
   }
 
@@ -1985,12 +1985,12 @@
   if (this->GlobalGenerator->TargetsWindowsPhone() ||
       this->GlobalGenerator->TargetsWindowsStore()) {
     cmProp content = sf->GetProperty("VS_DEPLOYMENT_CONTENT");
-    if (content && !content->empty()) {
+    if (cmNonempty(content)) {
       toolHasSettings = true;
       deployContent = *content;
 
       cmProp location = sf->GetProperty("VS_DEPLOYMENT_LOCATION");
-      if (location && !location->empty()) {
+      if (cmNonempty(location)) {
         deployLocation = *location;
       }
     }
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index 0e3cf08..55e941d 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -324,8 +324,7 @@
   bool defaultValue)
 {
   cmProp property = Target->GetTarget()->GetProperty(varName);
-  bool isOn =
-    (property == nullptr && defaultValue) || (property && cmIsOn(*property));
+  bool isOn = (property == nullptr && defaultValue) || cmIsOn(property);
 
   if (isOn) {
     xout.Attribute(attrName.c_str(), "YES");
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 2656849..45fa44b 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -1487,10 +1487,10 @@
   this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(*value));
 
   value = this->State->GetCacheEntryValue("CMAKE_ERROR_DEPRECATED");
-  this->Messenger->SetDeprecatedWarningsAsErrors(value && cmIsOn(*value));
+  this->Messenger->SetDeprecatedWarningsAsErrors(cmIsOn(value));
 
   value = this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_WARNINGS");
-  this->Messenger->SetSuppressDevWarnings(value && cmIsOn(*value));
+  this->Messenger->SetSuppressDevWarnings(cmIsOn(value));
 
   value = this->State->GetCacheEntryValue("CMAKE_SUPPRESS_DEVELOPER_ERRORS");
   this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(*value));
@@ -2742,9 +2742,7 @@
   }
   projName = *cachedProjectName;
 
-  cmProp cachedVerbose =
-    this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE");
-  if (cachedVerbose && cmIsOn(*cachedVerbose)) {
+  if (cmIsOn(this->State->GetCacheEntryValue("CMAKE_VERBOSE_MAKEFILE"))) {
     verbose = true;
   }
 
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 3419807..7c66c5c 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -98,7 +98,9 @@
     "Find problems with variable usage in system "
     "files." },
 #  if !defined(CMAKE_BOOTSTRAP)
-  { "--profiling-format=<fmt>", "Output data for profiling CMake scripts." },
+  { "--profiling-format=<fmt>",
+    "Output data for profiling CMake scripts. Supported formats: "
+    "google-trace" },
   { "--profiling-output=<file>",
     "Select an output path for the profiling data enabled through "
     "--profiling-format." },
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 49e8a4f..1a5fea1 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -126,6 +126,7 @@
     << "  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"
 #if defined(_WIN32) && !defined(__CYGWIN__)
@@ -1034,6 +1035,34 @@
       return 0;
     }
 
+    // Command to create a hard link.  Fails on platforms not
+    // supporting them.
+    if (args[1] == "create_hardlink" && args.size() == 4) {
+      const char* SouceFileName = args[2].c_str();
+      const char* destinationFileName = args[3].c_str();
+
+      if (!cmSystemTools::FileExists(SouceFileName)) {
+        std::cerr << "failed to create hard link because source path '"
+                  << SouceFileName << "' does not exist \n";
+        return 1;
+      }
+
+      if ((cmSystemTools::FileExists(destinationFileName) ||
+           cmSystemTools::FileIsSymlink(destinationFileName)) &&
+          !cmSystemTools::RemoveFile(destinationFileName)) {
+        std::string emsg = cmSystemTools::GetLastSystemError();
+        std::cerr << "failed to create hard link '" << destinationFileName
+                  << "' because existing path cannot be removed: " << emsg
+                  << "\n";
+        return 1;
+      }
+
+      if (!cmSystemTools::CreateLink(args[2], args[3])) {
+        return 1;
+      }
+      return 0;
+    }
+
     // Command to do nothing with an exit code of 0.
     if (args[1] == "true") {
       return 0;
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index bb50d76..0b2c8f6 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -29,6 +29,9 @@
   testCMExtMemory.cxx
   testCMExtAlgorithm.cxx
   )
+if (CMake_TEST_FILESYSTEM_PATH OR NOT CMake_HAVE_CXX_FILESYSTEM)
+  list(APPEND CMakeLib_TESTS testCMFilesystemPath.cxx)
+endif()
 
 add_executable(testUVProcessChainHelper testUVProcessChainHelper.cxx)
 
diff --git a/Tests/CMakeLib/PseudoMemcheck/CMakeLists.txt b/Tests/CMakeLib/PseudoMemcheck/CMakeLists.txt
index 7c84ee1..4bef6c5 100644
--- a/Tests/CMakeLib/PseudoMemcheck/CMakeLists.txt
+++ b/Tests/CMakeLib/PseudoMemcheck/CMakeLists.txt
@@ -15,6 +15,9 @@
 add_executable(pseudo_BC "${CMAKE_CURRENT_BINARY_DIR}/ret0.cxx")
 set_target_properties(pseudo_BC PROPERTIES OUTPUT_NAME BC)
 target_link_libraries(pseudo_BC CMakeLib)
+add_executable(pseudo_cuda-memcheck "${CMAKE_CURRENT_BINARY_DIR}/ret0.cxx")
+set_target_properties(pseudo_cuda-memcheck PROPERTIES OUTPUT_NAME cuda-memcheck)
+target_link_libraries(pseudo_cuda-memcheck CMakeLib)
 
 # binary to be used as pre- and post-memcheck command that fails
 add_executable(memcheck_fail "${CMAKE_CURRENT_BINARY_DIR}/ret1.cxx")
diff --git a/Tests/CMakeLib/PseudoMemcheck/memtester.cxx.in b/Tests/CMakeLib/PseudoMemcheck/memtester.cxx.in
index 3183bc0..f37ad59 100644
--- a/Tests/CMakeLib/PseudoMemcheck/memtester.cxx.in
+++ b/Tests/CMakeLib/PseudoMemcheck/memtester.cxx.in
@@ -1,8 +1,14 @@
-#include <cmSystemTools.h>
-#include "cmsys/Encoding.hxx"
 #include <string>
+#include <vector>
 
+#include "cmsys/Encoding.hxx"
+
+#include <cmSystemTools.h>
+
+// clang-format off
 #define RETVAL @_retval@
+#define CMAKE_COMMAND "@CMAKE_COMMAND@"
+// clang-format on
 
 int main(int ac, char** av)
 {
@@ -14,6 +20,9 @@
   std::string exename = argv[0];
   std::string logarg;
   bool nextarg = false;
+  // execute the part after the last argument?
+  // the logfile path gets passed as environment variable PSEUDO_LOGFILE
+  bool exec = false;
 
   if (exename.find("valgrind") != std::string::npos) {
     logarg = "--log-file=";
@@ -26,6 +35,10 @@
   } else if (exename.find("BC") != std::string::npos) {
     nextarg = true;
     logarg = "/X";
+  } else if (exename.find("cuda-memcheck") != std::string::npos) {
+    nextarg = true;
+    exec = true;
+    logarg = "--log-file";
   }
 
   if (!logarg.empty()) {
@@ -45,8 +58,25 @@
       }
     }
 
+    // find the last argument position
+    int lastarg_pos = 1;
+    for (int i = 1; i < argc; ++i) {
+      std::string arg = argv[i];
+      if (arg.find("--") == 0) {
+        lastarg_pos = i;
+      }
+    }
+
     if (!logfile.empty()) {
       cmSystemTools::Touch(logfile, true);
+      // execute everything after the last argument with additional environment
+      int callarg_pos = lastarg_pos + (nextarg ? 2 : 1);
+      if (exec && callarg_pos < argc) {
+        std::vector<std::string> callargs{ CMAKE_COMMAND, "-E", "env",
+                                           "PSEUDO_LOGFILE=" + logfile };
+        callargs.insert(callargs.end(), &argv[callarg_pos], &argv[argc]);
+        cmSystemTools::RunSingleCommand(callargs);
+      }
     }
   }
 
diff --git a/Tests/CMakeLib/testCMFilesystemPath.cxx b/Tests/CMakeLib/testCMFilesystemPath.cxx
new file mode 100644
index 0000000..1e84520
--- /dev/null
+++ b/Tests/CMakeLib/testCMFilesystemPath.cxx
@@ -0,0 +1,1006 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <cm/filesystem>
+#include <cm/iomanip>
+
+namespace {
+
+namespace fs = cm::filesystem;
+
+void checkResult(bool success)
+{
+  if (!success) {
+    std::cout << " => failed";
+  }
+  std::cout << std::endl;
+}
+
+bool testConstructors()
+{
+  std::cout << "testConstructors()";
+
+  bool result = true;
+
+  {
+    fs::path p;
+    if (p != fs::path()) {
+      result = false;
+    }
+  }
+  {
+    fs::path p1("/a/b/c");
+    fs::path p2("/a/b/c");
+    if (p1 != p2) {
+      result = false;
+    }
+    if (p1.string() != p2.string()) {
+      result = false;
+    }
+    if (p1.string() != "/a/b/c") {
+      result = false;
+    }
+  }
+  {
+    std::string s("/a/b/c");
+    fs::path p1(s);
+    fs::path p2(s.begin(), s.end());
+    if (p1 != p2) {
+      result = false;
+    }
+    if (p1.string() != s || p2.string() != s) {
+      result = false;
+    }
+#if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
+    std::string s2(s);
+    s2 += '\0';
+    fs::path p3(s2.begin());
+    if (p1 != p3 || p3.string() != s) {
+      result = false;
+    }
+#endif
+  }
+  {
+    std::wstring s(L"/a/b/c");
+    fs::path p1(s);
+    fs::path p2(s.begin(), s.end());
+    if (p1 != p2) {
+      result = false;
+    }
+    if (p1.wstring() != s || p2.wstring() != s) {
+      result = false;
+    }
+#if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
+    std::wstring s2(s);
+    s2 += L'\0';
+    fs::path p3(s2.begin());
+    if (p1 != p3 || p3.wstring() != s) {
+      result = false;
+    }
+#endif
+  }
+  {
+    std::string s("/a/b/c");
+    fs::path::string_type ws;
+    for (auto c : s) {
+      ws += fs::path::value_type(c);
+    }
+    fs::path p1(ws);
+    fs::path p2(ws.begin(), ws.end());
+    if (p1 != p2) {
+      result = false;
+    }
+    if (p1.native() != ws || p2.native() != ws) {
+      result = false;
+    }
+#if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
+    fs::path::string_type ws2(ws);
+    ws2 += fs::path::value_type('\0');
+    fs::path p3(ws2.begin());
+    if (p1 != p3 || p3.native() != ws) {
+      result = false;
+    }
+#endif
+  }
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testConcatenation()
+{
+  std::cout << "testConcatenation()";
+
+  bool result = true;
+
+  {
+    fs::path p("/a/b");
+    p /= "c";
+    if (!(p.string() == "/a/b/c" || p.string() == "/a/b\\c")) {
+      result = false;
+    }
+    p += "d";
+    if (!(p.string() == "/a/b/cd" || p.string() == "/a/b\\cd")) {
+      result = false;
+    }
+    fs::path p2("x/y");
+    p /= p2;
+    if (!(p.string() == "/a/b/cd/x/y" || p.string() == "/a/b\\cd\\x/y")) {
+      result = false;
+    }
+    p = p / p2;
+    if (!(p.string() == "/a/b/cd/x/y/x/y" ||
+          p.string() == "/a/b\\cd\\x/y\\x/y")) {
+      result = false;
+    }
+  }
+  {
+    fs::path p("a");
+    p /= "";
+    if (!(p.string() == "a/" || p.string() == "a\\")) {
+      result = false;
+    }
+    p /= "/b";
+    if (p.string() != "/b") {
+      result = false;
+    }
+  }
+#if defined(_WIN32)
+  {
+    fs::path p("a");
+    p /= "c:/b";
+    if (p.string() != "c:/b") {
+      result = false;
+    }
+    p = fs::path("a") / "c:";
+    if (p.string() != "c:") {
+      result = false;
+    }
+    p = fs::path("c:") / "";
+    if (p.string() != "c:") {
+      result = false;
+    }
+    p = fs::path("c:a") / "/b";
+    if (p.string() != "c:/b") {
+      result = false;
+    }
+    p = fs::path("c:a") / "c:b";
+    if (p.string() != "c:a\\b") {
+      result = false;
+    }
+    p = fs::path("//host") / "b";
+    if (p.string() != "//host\\b") {
+      result = false;
+    }
+    p = fs::path("//host/") / "b";
+    if (p.string() != "//host/b") {
+      result = false;
+    }
+  }
+#endif
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testModifiers()
+{
+  std::cout << "testModifiers()";
+
+  bool result = true;
+
+  {
+    std::string s("a///b/");
+    fs::path p(s);
+    std::replace(
+      s.begin(), s.end(), '/',
+      static_cast<std::string::value_type>(fs::path::preferred_separator));
+    p.make_preferred();
+    if (p.string() != s) {
+      result = false;
+    }
+  }
+  {
+    fs::path p("a/b/c.e.f");
+    p.remove_filename();
+    if (p.string() != "a/b/") {
+      result = false;
+    }
+    p.remove_filename();
+    if (p.string() != "a/b/") {
+      result = false;
+    }
+  }
+  {
+    fs::path p("a/b/c.e.f");
+    p.replace_filename("x.y");
+    if (p.string() != "a/b/x.y") {
+      result = false;
+    }
+  }
+  {
+    fs::path p("a/b/c.e.f");
+    p.replace_extension(".x");
+    if (p.string() != "a/b/c.e.x") {
+      result = false;
+    }
+    p.replace_extension(".y");
+    if (p.string() != "a/b/c.e.y") {
+      result = false;
+    }
+    p.replace_extension();
+    if (p.string() != "a/b/c.e") {
+      result = false;
+    }
+    p = "/a/b";
+    p.replace_extension(".x");
+    if (p.string() != "/a/b.x") {
+      result = false;
+    }
+    p = "/a/b/";
+    p.replace_extension(".x");
+    if (p.string() != "/a/b/.x") {
+      result = false;
+    }
+  }
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testObservers()
+{
+  std::cout << "testObservers()";
+
+  bool result = true;
+
+  {
+    std::string s("a/b/c");
+    fs::path p(s);
+    fs::path::string_type st;
+    for (auto c : s) {
+      st += static_cast<fs::path::value_type>(c);
+    }
+    if (p.native() != st || static_cast<fs::path::string_type>(p) != st ||
+        p.c_str() != st) {
+      result = false;
+    }
+  }
+  {
+    std::string s("a//b//c");
+    std::wstring ws(L"a//b//c");
+    fs::path p(s);
+    if (p.string() != s || p.wstring() != ws) {
+      result = false;
+    }
+  }
+  {
+    std::string s("a/b/c");
+    std::wstring ws;
+    for (auto c : s) {
+      ws += static_cast<std::wstring::value_type>(c);
+    }
+    std::string ns(s);
+    std::replace(
+      ns.begin(), ns.end(), '/',
+      static_cast<std::string::value_type>(fs::path::preferred_separator));
+    fs::path p(ns);
+    if (p.generic_string() != s || p.generic_wstring() != ws) {
+      result = false;
+    }
+  }
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testCompare()
+{
+  std::cout << "testCompare()";
+
+  bool result = true;
+
+  {
+    std::string s("a/b/c");
+    fs::path p1(s);
+    fs::path p2(s);
+    if (p1.compare(p2) != 0) {
+      result = false;
+    }
+    p2 = "a/b";
+    if (p1.compare(p2) <= 0) {
+      result = false;
+    }
+    p2 = "a/d";
+    if (p1.compare(p2) >= 0) {
+      result = false;
+    }
+    p2 = "a/b/d";
+    if (p1.compare(p2) >= 0) {
+      result = false;
+    }
+    p2 = "a/b/a";
+    if (p1.compare(p2) <= 0) {
+      result = false;
+    }
+    p2 = "a/b/c/d";
+    if (p1.compare(p2) >= 0) {
+      result = false;
+    }
+    p1 = "a";
+    p2 = "b";
+    if (p1.compare(p2) == 0) {
+      result = false;
+    }
+  }
+  {
+    // LWG 3096 (https://cplusplus.github.io/LWG/issue3096)
+    // fs::path p1("/a/");
+    // fs::path p2("/a/.");
+    // if (p1.compare(p2) != 0) {
+    //   result = false;
+    // }
+  }
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testGeneration()
+{
+  std::cout << "testGeneration()";
+
+  bool result = true;
+
+  {
+    fs::path p("a/./b/..");
+    if (p.lexically_normal().generic_string() != "a/") {
+      result = false;
+    }
+    p = "a/.///b/../";
+    if (p.lexically_normal().generic_string() != "a/") {
+      result = false;
+    }
+  }
+#if defined(_WIN32)
+  {
+    fs::path p("//host/./b/..");
+    if (p.lexically_normal().string() != "\\\\host\\") {
+      result = false;
+    }
+    p = "//host/.///b/../";
+    if (p.lexically_normal().string() != "\\\\host\\") {
+      result = false;
+    }
+    p = "c://a/.///b/../";
+    if (p.lexically_normal().string() != "c:\\a\\") {
+      result = false;
+    }
+  }
+#endif
+
+  {
+    if (fs::path("/a//d").lexically_relative("/a/b/c") != "../../d") {
+      result = false;
+    }
+    if (fs::path("/a//b///c").lexically_relative("/a/d") != "../b/c") {
+      result = false;
+    }
+    if (fs::path("a/b/c").lexically_relative("a") != "b/c") {
+      result = false;
+    }
+    if (fs::path("a/b/c").lexically_relative("a/b/c/x/y") != "../..") {
+      result = false;
+    }
+    if (fs::path("a/b/c").lexically_relative("a/b/c") != ".") {
+      result = false;
+    }
+    if (fs::path("a/b").lexically_relative("c/d") != "../../a/b") {
+      result = false;
+    }
+  }
+  {
+#if defined(_WIN32)
+    if (fs::path("/a/d").lexically_relative("e/d/c") != "/a/d") {
+      result = false;
+    }
+    if (!fs::path("c:/a/d").lexically_relative("e/d/c").empty()) {
+      result = false;
+    }
+#else
+    if (!fs::path("/a/d").lexically_relative("e/d/c").empty()) {
+      result = false;
+    }
+#endif
+  }
+  {
+#if defined(_WIN32)
+    if (fs::path("c:/a/d").lexically_proximate("e/d/c") != "c:/a/d") {
+      result = false;
+    }
+#else
+    if (fs::path("/a/d").lexically_proximate("e/d/c") != "/a/d") {
+      result = false;
+    }
+#endif
+    if (fs::path("/a/d").lexically_proximate("/a/b/c") != "../../d") {
+      result = false;
+    }
+  }
+  // LWG 3070
+  {
+#if defined(_WIN32)
+    if (!fs::path("/a:/b:").lexically_relative("/a:/c:").empty()) {
+      result = false;
+    }
+    if (fs::path("c:/a/b").lexically_relative("c:/a/d") != "../b") {
+      result = false;
+    }
+    if (!fs::path("c:/a/b:").lexically_relative("c:/a/d").empty()) {
+      result = false;
+    }
+    if (!fs::path("c:/a/b").lexically_relative("c:/a/d:").empty()) {
+      result = false;
+    }
+#else
+    if (fs::path("/a:/b:").lexically_relative("/a:/c:") != "../b:") {
+      result = false;
+    }
+#endif
+  }
+  // LWG 3096
+  {
+    if (fs::path("/a").lexically_relative("/a/.") != ".") {
+      result = false;
+    }
+    if (fs::path("/a").lexically_relative("/a/") != ".") {
+      result = false;
+    }
+    if (fs::path("a/b/c").lexically_relative("a/b/c") != ".") {
+      result = false;
+    }
+    if (fs::path("a/b/c").lexically_relative("a/b/c/") != ".") {
+      result = false;
+    }
+    if (fs::path("a/b/c").lexically_relative("a/b/c/.") != ".") {
+      result = false;
+    }
+    if (fs::path("a/b/c/").lexically_relative("a/b/c") != ".") {
+      result = false;
+    }
+    if (fs::path("a/b/c/.").lexically_relative("a/b/c") != ".") {
+      result = false;
+    }
+    if (fs::path("a/b/c/.").lexically_relative("a/b/c/") != ".") {
+      result = false;
+    }
+  }
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testDecomposition()
+{
+  std::cout << "testDecomposition()";
+
+  bool result = true;
+
+  {
+    if (!fs::path("/a/b").root_name().empty()) {
+      result = false;
+    }
+#if defined(_WIN32)
+    if (fs::path("c:/a/b").root_name() != "c:") {
+      result = false;
+    }
+    if (fs::path("c:a/b").root_name() != "c:") {
+      result = false;
+    }
+    if (fs::path("c:").root_name() != "c:") {
+      result = false;
+    }
+    if (fs::path("//host/b").root_name() != "//host") {
+      result = false;
+    }
+    if (fs::path("//host").root_name() != "//host") {
+      result = false;
+    }
+#endif
+  }
+  {
+    if (!fs::path("a/b").root_directory().empty()) {
+      result = false;
+    }
+    if (fs::path("/a/b").root_directory() != "/") {
+      result = false;
+    }
+#if defined(_WIN32)
+    if (!fs::path("c:a/b").root_directory().empty()) {
+      result = false;
+    }
+    if (fs::path("/a/b").root_directory() != "/") {
+      result = false;
+    }
+    if (fs::path("c:/a/b").root_directory() != "/") {
+      result = false;
+    }
+    if (fs::path("//host/b").root_directory() != "/") {
+      result = false;
+    }
+#endif
+  }
+  {
+    if (!fs::path("a/b").root_path().empty()) {
+      result = false;
+    }
+    if (fs::path("/a/b").root_path() != "/") {
+      result = false;
+    }
+#if defined(_WIN32)
+    if (fs::path("c:a/b").root_path() != "c:") {
+      result = false;
+    }
+    if (fs::path("/a/b").root_path() != "/") {
+      result = false;
+    }
+    if (fs::path("c:/a/b").root_path() != "c:/") {
+      result = false;
+    }
+    if (fs::path("//host/b").root_path() != "//host/") {
+      result = false;
+    }
+#endif
+  }
+  {
+    if (!fs::path("/").relative_path().empty()) {
+      result = false;
+    }
+    if (fs::path("a/b").relative_path() != "a/b") {
+      result = false;
+    }
+    if (fs::path("/a/b").relative_path() != "a/b") {
+      result = false;
+    }
+#if defined(_WIN32)
+    if (fs::path("c:a/b").relative_path() != "a/b") {
+      result = false;
+    }
+    if (fs::path("/a/b").relative_path() != "a/b") {
+      result = false;
+    }
+    if (fs::path("c:/a/b").relative_path() != "a/b") {
+      result = false;
+    }
+    if (fs::path("//host/b").relative_path() != "b") {
+      result = false;
+    }
+#endif
+  }
+  {
+    if (fs::path("/a/b").parent_path() != "/a") {
+      result = false;
+    }
+    if (fs::path("/a/b/").parent_path() != "/a/b") {
+      result = false;
+    }
+    if (fs::path("/a/b/.").parent_path() != "/a/b") {
+      result = false;
+    }
+    if (fs::path("/").parent_path() != "/") {
+      result = false;
+    }
+#if defined(_WIN32)
+    if (fs::path("c:/a/b").parent_path() != "c:/a") {
+      result = false;
+    }
+    if (fs::path("c:/").parent_path() != "c:/") {
+      result = false;
+    }
+    if (fs::path("c:").parent_path() != "c:") {
+      result = false;
+    }
+    if (fs::path("//host/").parent_path() != "//host/") {
+      result = false;
+    }
+    if (fs::path("//host").parent_path() != "//host") {
+      result = false;
+    }
+#endif
+  }
+  {
+    if (fs::path("/a/b.txt").filename() != "b.txt") {
+      result = false;
+    }
+    if (fs::path("/a/.b").filename() != ".b") {
+      result = false;
+    }
+    if (fs::path("/foo/bar/").filename() != "") {
+      result = false;
+    }
+    if (fs::path("/foo/.").filename() != ".") {
+      result = false;
+    }
+    if (fs::path("/foo/..").filename() != "..") {
+      result = false;
+    }
+    if (fs::path(".").filename() != ".") {
+      result = false;
+    }
+    if (fs::path("..").filename() != "..") {
+      result = false;
+    }
+    if (!fs::path("/").filename().empty()) {
+      result = false;
+    }
+#if defined(_WIN32)
+    if (fs::path("c:a").filename() != "a") {
+      result = false;
+    }
+    if (fs::path("c:/a").filename() != "a") {
+      result = false;
+    }
+    if (!fs::path("c:").filename().empty()) {
+      result = false;
+    }
+    if (!fs::path("c:/").filename().empty()) {
+      result = false;
+    }
+    if (!fs::path("//host").filename().empty()) {
+      result = false;
+    }
+#endif
+  }
+  {
+    if (fs::path("/a/b.txt").stem() != "b") {
+      result = false;
+    }
+    if (fs::path("/a/b.c.txt").stem() != "b.c") {
+      result = false;
+    }
+    if (fs::path("/a/.b").stem() != ".b") {
+      result = false;
+    }
+    if (fs::path("/a/b").stem() != "b") {
+      result = false;
+    }
+    if (fs::path("/a/b/.").stem() != ".") {
+      result = false;
+    }
+    if (fs::path("/a/b/..").stem() != "..") {
+      result = false;
+    }
+    if (!fs::path("/a/b/").stem().empty()) {
+      result = false;
+    }
+#if defined(_WIN32)
+    if (!fs::path("c:/a/b/").stem().empty()) {
+      result = false;
+    }
+    if (!fs::path("c:/").stem().empty()) {
+      result = false;
+    }
+    if (!fs::path("c:").stem().empty()) {
+      result = false;
+    }
+    if (!fs::path("//host/").stem().empty()) {
+      result = false;
+    }
+    if (!fs::path("//host").stem().empty()) {
+      result = false;
+    }
+#endif
+  }
+  {
+    if (fs::path("/a/b.txt").extension() != ".txt") {
+      result = false;
+    }
+    if (fs::path("/a/b.").extension() != ".") {
+      result = false;
+    }
+    if (!fs::path("/a/b").extension().empty()) {
+      result = false;
+    }
+    if (fs::path("/a/b.txt/b.cc").extension() != ".cc") {
+      result = false;
+    }
+    if (fs::path("/a/b.txt/b.").extension() != ".") {
+      result = false;
+    }
+    if (!fs::path("/a/b.txt/b").extension().empty()) {
+      result = false;
+    }
+    if (!fs::path("/a/.").extension().empty()) {
+      result = false;
+    }
+    if (!fs::path("/a/..").extension().empty()) {
+      result = false;
+    }
+    if (!fs::path("/a/.hidden").extension().empty()) {
+      result = false;
+    }
+    if (fs::path("/a/..b").extension() != ".b") {
+      result = false;
+    }
+  }
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testQueries()
+{
+  std::cout << "testQueries()";
+
+  bool result = true;
+
+  {
+    if (fs::path("/a/b").has_root_name()) {
+      result = false;
+    }
+    fs::path p("/a/b");
+    if (!p.has_root_directory() || !p.has_root_path()) {
+      result = false;
+    }
+    if (!fs::path("/a/b").has_root_path() || fs::path("a/b").has_root_path()) {
+      result = false;
+    }
+    if (!fs::path("/a/b").has_relative_path() ||
+        fs::path("/").has_relative_path()) {
+      result = false;
+    }
+    if (!fs::path("/a/b").has_parent_path() ||
+        !fs::path("/").has_parent_path() || fs::path("a").has_parent_path()) {
+      result = false;
+    }
+    if (!fs::path("/a/b").has_filename() || !fs::path("a.b").has_filename() ||
+        fs::path("/a/").has_filename() || fs::path("/").has_filename()) {
+      result = false;
+    }
+    if (!fs::path("/a/b").has_stem() || !fs::path("a.b").has_stem() ||
+        !fs::path("/.a").has_stem() || fs::path("/a/").has_stem() ||
+        fs::path("/").has_stem()) {
+      result = false;
+    }
+    if (!fs::path("/a/b.c").has_extension() ||
+        !fs::path("a.b").has_extension() || fs::path("/.a").has_extension() ||
+        fs::path("/a/").has_extension() || fs::path("/").has_extension()) {
+      result = false;
+    }
+#if defined(_WIN32)
+    p = "c:/a/b";
+    if (!fs::path("c:/a/b").has_root_name() || !p.has_root_directory() ||
+        !p.has_root_path()) {
+      result = false;
+    }
+    p = "c:a/b";
+    if (!p.has_root_name() || p.has_root_directory() || !p.has_root_path()) {
+      result = false;
+    }
+    p = "//host/b";
+    if (!p.has_root_name() || !p.has_root_directory() || !p.has_root_path()) {
+      result = false;
+    }
+    p = "//host";
+    if (!p.has_root_name() || p.has_root_directory() || !p.has_root_path()) {
+      result = false;
+    }
+    if (!fs::path("c:/a/b").has_relative_path() ||
+        !fs::path("c:a/b").has_relative_path() ||
+        !fs::path("//host/b").has_relative_path()) {
+      result = false;
+    }
+    if (!fs::path("c:/a/b").has_parent_path() ||
+        !fs::path("c:/").has_parent_path() ||
+        !fs::path("c:").has_parent_path() ||
+        !fs::path("//host/").has_parent_path() ||
+        !fs::path("//host").has_parent_path()) {
+      result = false;
+    }
+#endif
+  }
+  {
+#if defined(_WIN32)
+    fs::path p("c:/a");
+#else
+    fs::path p("/a");
+#endif
+    if (!p.is_absolute() || p.is_relative()) {
+      result = false;
+    }
+    p = "a/b";
+    if (p.is_absolute() || !p.is_relative()) {
+      result = false;
+    }
+#if defined(_WIN32)
+    p = "c:/a/b";
+    if (!p.is_absolute() || p.is_relative()) {
+      result = false;
+    }
+    p = "//host/b";
+    if (!p.is_absolute() || p.is_relative()) {
+      result = false;
+    }
+    p = "/a";
+    if (p.is_absolute() || !p.is_relative()) {
+      result = false;
+    }
+    p = "c:a";
+    if (p.is_absolute() || !p.is_relative()) {
+      result = false;
+    }
+#endif
+  }
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testIterators()
+{
+  std::cout << "testIterators()";
+
+  bool result = true;
+
+  {
+    fs::path p("/a/b/");
+#if defined(_WIN32)
+    std::vector<fs::path::string_type> ref{ L"/", L"a", L"b", L"" };
+#else
+    std::vector<fs::path::string_type> ref{ "/", "a", "b", "" };
+#endif
+    std::vector<fs::path::string_type> res;
+    for (auto i = p.begin(), e = p.end(); i != e; ++i) {
+      res.push_back(*i);
+    }
+    if (res != ref) {
+      result = false;
+    }
+    res.clear();
+    for (const auto& e : p) {
+      res.push_back(e);
+    }
+    if (res != ref) {
+      result = false;
+    }
+  }
+  {
+    fs::path p("/a/b/");
+#if defined(_WIN32)
+    std::vector<fs::path::string_type> ref{ L"", L"b", L"a", L"/" };
+#else
+    std::vector<fs::path::string_type> ref{ "", "b", "a", "/" };
+#endif
+    std::vector<fs::path::string_type> res;
+    auto i = p.end(), b = p.begin();
+    do {
+      res.push_back(*--i);
+    } while (i != b);
+    if (res != ref) {
+      result = false;
+    }
+  }
+
+  checkResult(result);
+
+  return result;
+}
+
+bool testNonMemberFunctions()
+{
+  std::cout << "testNonMemberFunctions()";
+
+  bool result = true;
+
+  {
+    fs::path p1("/a/b/");
+    fs::path p2("/c/d");
+    fs::swap(p1, p2);
+    if (p1.string() != "/c/d" || p2.string() != "/a/b/")
+      result = false;
+  }
+  {
+    auto h1 = fs::hash_value(fs::path("/a//b//"));
+    auto h2 = fs::hash_value(fs::path("/a/b/"));
+    if (h1 != h2)
+      result = false;
+  }
+  {
+    fs::path p1("/a/b/");
+    fs::path p2("/c/d");
+    if (p1 == p2)
+      result = false;
+    p1 = "/a//b//";
+    p2 = "/a/b/";
+    if (p1 != p2)
+      result = false;
+  }
+  {
+    fs::path p = "/a";
+    p = p / "b" / "c";
+    if (p.generic_string() != "/a/b/c") {
+      result = false;
+    }
+    fs::path::string_type ref;
+    ref += fs::path::value_type('/');
+    ref += fs::path::value_type('a');
+    ref += fs::path::preferred_separator;
+    ref += fs::path::value_type('b');
+    ref += fs::path::preferred_separator;
+    ref += fs::path::value_type('c');
+    if (p.native() != ref) {
+      result = false;
+    }
+  }
+  {
+    fs::path p("/a b\\c/");
+    std::ostringstream oss;
+    oss << p;
+    if (oss.str() != "\"/a b\\\\c/\"") {
+      result = false;
+    }
+    std::istringstream iss(oss.str());
+    fs::path p2;
+    iss >> p2;
+    if (p2 != p) {
+      result = false;
+    }
+  }
+
+  checkResult(result);
+
+  return result;
+}
+}
+
+int testCMFilesystemPath(int /*unused*/, char* /*unused*/ [])
+{
+  int result = 0;
+
+  if (!testConstructors()) {
+    result = 1;
+  }
+  if (!testConcatenation()) {
+    result = 1;
+  }
+  if (!testModifiers()) {
+    result = 1;
+  }
+  if (!testObservers()) {
+    result = 1;
+  }
+  if (!testCompare()) {
+    result = 1;
+  }
+  if (!testGeneration()) {
+    result = 1;
+  }
+  if (!testDecomposition()) {
+    result = 1;
+  }
+  if (!testQueries()) {
+    result = 1;
+  }
+  if (!testIterators()) {
+    result = 1;
+  }
+  if (!testNonMemberFunctions()) {
+    result = 1;
+  }
+
+  return result;
+}
diff --git a/Tests/FindPackageModeMakefileTest/Makefile.in b/Tests/FindPackageModeMakefileTest/Makefile.in
index 5ef67d0..af9fa96 100644
--- a/Tests/FindPackageModeMakefileTest/Makefile.in
+++ b/Tests/FindPackageModeMakefileTest/Makefile.in
@@ -24,7 +24,7 @@
 pngtest: main.o
 	@$(CMAKE_FOO) -DMODE=LINK >$(tmp)
 	@foo="`cat $(tmp)`"; \
-	 printf '"%s" %s %s -o pngtest main.o %s\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(LDFLAGS)" "$$foo" >$(tmp)
+	 printf '"%s" %s %s %s -o pngtest main.o %s\n' $(CMAKE_CXX_COMPILER) "$(CMAKE_CXX_FLAGS)" "$(__EXTRA_OSX_SYSROOT_FLAGS)" "$(LDFLAGS)" "$$foo" >$(tmp)
 	@cat $(tmp)
 	@sh $(tmp)
 	@rm -f $(tmp)
diff --git a/Tests/FindX11/Test/CMakeLists.txt b/Tests/FindX11/Test/CMakeLists.txt
index b2adfb2..7325b32 100644
--- a/Tests/FindX11/Test/CMakeLists.txt
+++ b/Tests/FindX11/Test/CMakeLists.txt
@@ -29,6 +29,7 @@
 set(X11_X11_FOUND ${X11_FOUND})
 test_x11_component(x11_components X11)
 test_x11_component(x11_components Xau)
+test_x11_component(x11_components Xaw)
 test_x11_component(x11_components xcb)
 test_x11_component(x11_components X11_xcb)
 test_x11_component(x11_components xcb_icccm)
@@ -67,6 +68,7 @@
 # Not included in X11_LIBRARIES.
 foreach(lib
     Xau
+    Xaw
     xcb
     X11_xcb
     xcb_icccm
diff --git a/Tests/FindX11/Test/main.c b/Tests/FindX11/Test/main.c
index c8144e0..f8c723c 100644
--- a/Tests/FindX11/Test/main.c
+++ b/Tests/FindX11/Test/main.c
@@ -308,6 +308,24 @@
 }
 #endif
 
+#ifdef HAVE_X11_Xaw
+#  include <X11/Intrinsic.h>
+#  include <X11/Xaw/Box.h>
+
+static void test_Xaw(void)
+{
+  XrmOptionDescRec opt_table[] = { { NULL } };
+
+  Widget toplevel;
+  toplevel =
+    XtInitialize("test", "test", opt_table, XtNumber(opt_table), NULL, NULL);
+  Widget box =
+    XtCreateManagedWidget("testbox", boxWidgetClass, toplevel, NULL, 0);
+  return;
+}
+
+#endif
+
 #include <stddef.h>
 
 int main(int argc, char* argv[])
@@ -392,6 +410,9 @@
 #ifdef HAVE_X11_Xv
     test_Xv,
 #endif
+#ifdef HAVE_X11_Xaw
+    test_Xaw,
+#endif
     NULL,
   };
 
diff --git a/Tests/GeneratorExpression/check-part3.cmake b/Tests/GeneratorExpression/check-part3.cmake
index b5eafa6..5571c3d 100644
--- a/Tests/GeneratorExpression/check-part3.cmake
+++ b/Tests/GeneratorExpression/check-part3.cmake
@@ -9,11 +9,11 @@
 check(test_version_equal_2 "1")
 
 if(config AND NOT config STREQUAL NoConfig)
-  if(NOT "${test_imported_includes}" MATCHES "^;*/imported[12]/include/with space;*$")
+  if(NOT "${test_imported_includes}" MATCHES "^[^;]*/imported[12]/include/with space$")
     message(SEND_ERROR "test_imported_includes is not correct: ${test_imported_includes}")
   endif()
 else()
-  if(NOT "${test_imported_includes}" MATCHES "^;;$")
+  if(NOT "${test_imported_includes}" MATCHES "^$")
     message(SEND_ERROR "test_imported_includes is not an empty list: ${test_imported_includes}")
   endif()
 endif()
diff --git a/Tests/Properties/CMakeLists.txt b/Tests/Properties/CMakeLists.txt
index 74d99fa..162a178 100644
--- a/Tests/Properties/CMakeLists.txt
+++ b/Tests/Properties/CMakeLists.txt
@@ -261,6 +261,25 @@
     endif()
 endfunction()
 
+# Check that source file directory scopes are deduplicated.
+set_property(SOURCE "${CMAKE_CURRENT_BINARY_DIR}/src32.cpp"
+    DIRECTORY SubDir2 SubDir2 SubDir2
+    TARGET_DIRECTORY set_prop_lib_3 set_prop_lib_3 set_prop_lib_3
+    APPEND
+    PROPERTY NON_DUPLICATED_CUSTOM_PROP 1
+)
+
+get_property(actual
+             SOURCE "${CMAKE_CURRENT_BINARY_DIR}/src32.cpp"
+             DIRECTORY SubDir2
+             PROPERTY NON_DUPLICATED_CUSTOM_PROP)
+check_get_property_value("1")
+
+get_source_file_property(actual "${CMAKE_CURRENT_BINARY_DIR}/src32.cpp"
+                         TARGET_DIRECTORY set_prop_lib_3
+                         NON_DUPLICATED_CUSTOM_PROP)
+check_get_property_value("1")
+
 # Get property + target directory
 get_property(actual
              SOURCE "${src_prefix}/src1.cpp"
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 871e18f..422d475 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -163,6 +163,7 @@
     -DPSEUDO_BC=$<TARGET_FILE:pseudo_BC>
     -DPSEUDO_PURIFY=$<TARGET_FILE:pseudo_purify>
     -DPSEUDO_VALGRIND=$<TARGET_FILE:pseudo_valgrind>
+    -DPSEUDO_CUDA_MEMCHECK=$<TARGET_FILE:pseudo_cuda-memcheck>
     -DPSEUDO_BC_NOLOG=$<TARGET_FILE:pseudonl_BC>
     -DPSEUDO_PURIFY_NOLOG=$<TARGET_FILE:pseudonl_purify>
     -DPSEUDO_VALGRIND_NOLOG=$<TARGET_FILE:pseudonl_valgrind>
@@ -206,6 +207,7 @@
 if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles|Ninja")
   add_RunCMake_test(ExportCompileCommands)
 endif()
+add_RunCMake_test(ExcludeFromAll)
 add_RunCMake_test(ExternalData)
 add_RunCMake_test(FeatureSummary)
 add_RunCMake_test(FPHSA)
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-no-arg-result.txt b/Tests/RunCMake/CommandLine/E_create_hardlink-no-arg-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-no-arg-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-no-arg-stderr.txt b/Tests/RunCMake/CommandLine/E_create_hardlink-no-arg-stderr.txt
new file mode 100644
index 0000000..50d9b03
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-no-arg-stderr.txt
@@ -0,0 +1,3 @@
+^CMake Error: cmake version .*
+Usage: .* -E <command> \[arguments\.\.\.\]
+Available commands:
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-result.txt b/Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-stderr.txt b/Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-stderr.txt
new file mode 100644
index 0000000..21e60ee
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-stderr.txt
@@ -0,0 +1 @@
+^CMake Error: failed to create link .* no such file or directory
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-non-existent-source-result.txt b/Tests/RunCMake/CommandLine/E_create_hardlink-non-existent-source-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-non-existent-source-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-non-existent-source-stderr.txt b/Tests/RunCMake/CommandLine/E_create_hardlink-non-existent-source-stderr.txt
new file mode 100644
index 0000000..a334571
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-non-existent-source-stderr.txt
@@ -0,0 +1 @@
+^failed to create hard link because source path .* does not exist
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-prereq-check.cmake b/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-prereq-check.cmake
new file mode 100644
index 0000000..5b97aec
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-prereq-check.cmake
@@ -0,0 +1,3 @@
+if(${actual_stderr_var} MATCHES "operation not permitted")
+  unset(msg)
+endif()
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-result.txt b/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-stderr.txt b/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-stderr.txt
new file mode 100644
index 0000000..a334571
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-stderr.txt
@@ -0,0 +1 @@
+^failed to create hard link because source path .* does not exist
diff --git a/Tests/RunCMake/CommandLine/ProfilingTest-check.cmake b/Tests/RunCMake/CommandLine/ProfilingTest-check.cmake
index 19ece86..2e8eac1 100644
--- a/Tests/RunCMake/CommandLine/ProfilingTest-check.cmake
+++ b/Tests/RunCMake/CommandLine/ProfilingTest-check.cmake
@@ -16,3 +16,16 @@
   set(RunCMake_TEST_FAILED "Expected valid JSON end")
   return()
 endif()
+
+file(STRINGS ${ProfilingTestOutput} upperCaseCommand
+  REGEX [["name"[ ]*:[ ]*"__TESTING_COMMAND_CASE"]])
+if (NOT "${upperCaseCommand}" STREQUAL "")
+  set(RunCMake_TEST_FAILED "Command name not stored in lowercase")
+endif()
+file(STRINGS ${ProfilingTestOutput} lowerCaseCommand
+  REGEX [["name"[ ]*:[ ]*"__testing_command_case"]])
+list(LENGTH lowerCaseCommand numInvocations)
+if (NOT numInvocations EQUAL 1)
+  set(RunCMake_TEST_FAILED
+      "Unexpected number of lowercase command names: ${numInvocations}")
+endif()
diff --git a/Tests/RunCMake/CommandLine/ProfilingTest.cmake b/Tests/RunCMake/CommandLine/ProfilingTest.cmake
index 837f4bf..4cf0c30 100644
--- a/Tests/RunCMake/CommandLine/ProfilingTest.cmake
+++ b/Tests/RunCMake/CommandLine/ProfilingTest.cmake
@@ -1 +1,5 @@
-# This file is intentionally left blank
+function(__testing_command_case)
+endfunction()
+
+# This must not appear in the profiling output as uppercase
+__TESTING_COMMAND_CASE()
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 6d69945..b20e683 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -348,6 +348,42 @@
   ${CMAKE_COMMAND} -E create_symlink T .
   )
 
+#create hard link tests
+run_cmake_command(E_create_hardlink-no-arg
+  ${CMAKE_COMMAND} -E create_hardlink
+  )
+
+set(dir ${RunCMake_BINARY_DIR}/hardlink_tests)
+file(REMOVE_RECURSE "${dir}")
+file(MAKE_DIRECTORY ${dir})
+
+run_cmake_command(E_create_hardlink-non-existent-source
+  ${CMAKE_COMMAND} -E create_hardlink ${dir}/I_dont_exist ${dir}/link
+  )
+
+file(TOUCH ${dir}/1)
+
+run_cmake_command(E_create_hardlink-ok
+  ${CMAKE_COMMAND} -E create_hardlink ${dir}/1 ${dir}/1-link
+  )
+
+run_cmake_command(E_create_hardlink-no-directory
+  ${CMAKE_COMMAND} -E create_hardlink ${dir}/1 ${dir}/a/1-link
+  )
+
+#On Windows, if the user does not have sufficient privileges
+#don't fail this test
+set(RunCMake_DEFAULT_stderr "(operation not permitted)?")
+run_cmake_command(E_create_hardlink-unresolved-symlink-prereq
+  ${CMAKE_COMMAND} -E create_symlink ${dir}/1 ${dir}/1-symlink
+  )
+file(REMOVE ${dir}/1)
+
+run_cmake_command(E_create_hardlink-unresolved-symlink
+  ${CMAKE_COMMAND} -E create_hardlink ${dir}/1-symlink ${dir}/1s-link
+  )
+unset(RunCMake_DEFAULT_stderr)
+
 set(in ${RunCMake_SOURCE_DIR}/copy_input)
 set(out ${RunCMake_BINARY_DIR}/copy_output)
 file(REMOVE_RECURSE "${out}")
diff --git a/Tests/RunCMake/ExcludeFromAll/CMakeLists.txt b/Tests/RunCMake/ExcludeFromAll/CMakeLists.txt
new file mode 100644
index 0000000..74b3ff8
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.3)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/ExcludeFromAll/RunCMakeTest.cmake b/Tests/RunCMake/ExcludeFromAll/RunCMakeTest.cmake
new file mode 100644
index 0000000..25201e4
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/RunCMakeTest.cmake
@@ -0,0 +1,26 @@
+include(RunCMake)
+
+function(run_single_config_test label config exclude_from_all_value expectation)
+    set(case single-config)
+    message("-- Starting ${case} test: ${label}")
+    set(full_case_name "${case}-build-${config}")
+    set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${full_case_name}/")
+    run_cmake_with_options(${case}
+        -DCMAKE_BUILD_TYPE=${config}
+        -DTOOL_EXCLUDE_FROM_ALL=${exclude_from_all_value})
+    set(RunCMake_TEST_NO_CLEAN 1)
+    include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+    run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config ${config})
+endfunction()
+
+run_single_config_test("explictly not excluded" Debug 0 "should_exist")
+run_single_config_test("excluded" Debug 1 "should_not_exist")
+
+if(RunCMake_GENERATOR MATCHES "^(Xcode|Visual Studio)")
+    run_cmake(error-on-mixed-config)
+else()
+    run_single_config_test("explicitly not excluded with genex"
+        Release $<CONFIG:Debug> "should_exist")
+    run_single_config_test("excluded with genex"
+        Debug $<CONFIG:Debug> "should_not_exist")
+endif()
diff --git a/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-result.txt b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-stderr.txt b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-stderr.txt
new file mode 100644
index 0000000..eee5278
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config-stderr.txt
@@ -0,0 +1,3 @@
+CMake Error in CMakeLists.txt:
+  The EXCLUDED_FROM_ALL property of target "release_only_tool" varies by
+  configuration.  This is not supported by the "[^"]+"
diff --git a/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config.cmake b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config.cmake
new file mode 100644
index 0000000..6c0ed1d
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/error-on-mixed-config.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+
+set(CMAKE_CONFIGURATION_TYPES "Release;Debug" CACHE STRING "")
+
+add_executable(release_only_tool main.c)
+set_property(TARGET release_only_tool PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:Release>>")
diff --git a/Tests/RunCMake/ExcludeFromAll/main.c b/Tests/RunCMake/ExcludeFromAll/main.c
new file mode 100644
index 0000000..5047a34
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/main.c
@@ -0,0 +1,3 @@
+int main()
+{
+}
diff --git a/Tests/RunCMake/ExcludeFromAll/single-config-build-check.cmake b/Tests/RunCMake/ExcludeFromAll/single-config-build-check.cmake
new file mode 100644
index 0000000..1c455f2
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/single-config-build-check.cmake
@@ -0,0 +1,17 @@
+if(expectation STREQUAL "should_not_exist")
+    set(should_exist FALSE)
+elseif(expectation STREQUAL "should_exist")
+    set(should_exist TRUE)
+else()
+    message(FATAL_ERROR "Encountered unknown expectation: ${expectation}")
+endif()
+
+if(EXISTS "${TARGET_FILE_tool_${config}}")
+    if(NOT should_exist)
+        message(FATAL_ERROR "${TARGET_FILE_tool_${config}} should not exist.")
+    endif()
+else()
+    if(should_exist)
+        message(FATAL_ERROR "${TARGET_FILE_tool_${config}} should exist.")
+    endif()
+endif()
diff --git a/Tests/RunCMake/ExcludeFromAll/single-config.cmake b/Tests/RunCMake/ExcludeFromAll/single-config.cmake
new file mode 100644
index 0000000..71a9f06
--- /dev/null
+++ b/Tests/RunCMake/ExcludeFromAll/single-config.cmake
@@ -0,0 +1,11 @@
+enable_language(C)
+add_executable(tool main.c)
+set_property(TARGET tool PROPERTY EXCLUDE_FROM_ALL "${TOOL_EXCLUDE_FROM_ALL}")
+
+include(../NinjaMultiConfig/Common.cmake)
+set(orig_CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES})
+if("${CMAKE_CONFIGURATION_TYPES}" STREQUAL "")
+    set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE})
+endif()
+generate_output_files(tool)
+set(CMAKE_CONFIGURATION_TYPES ${orig_CMAKE_CONFIGURATION_TYPES})
diff --git a/Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-TARGET_PROPERTY.cmake b/Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-TARGET_PROPERTY.cmake
new file mode 100644
index 0000000..293ddda
--- /dev/null
+++ b/Tests/RunCMake/GenEx-COMPILE_LANGUAGE/COMPILE_LANGUAGE-TARGET_PROPERTY.cmake
@@ -0,0 +1,17 @@
+enable_language(C)
+
+add_library (lib SHARED empty.c)
+set_target_properties(lib PROPERTIES
+  INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:C>:/usr/include>"
+  COMPILE_DEFINITIONS "$<$<COMPILE_LANGUAGE:C>:DEF>"
+  COMPILE_OPTIONS "$<$<COMPILE_LANGUAGE:C>:-O>")
+
+add_custom_target(drive
+  COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:lib,INCLUDE_DIRECTORIES>
+                                   $<TARGET_PROPERTY:lib,COMPILE_DEFINITIONS>
+                                   $<TARGET_PROPERTY:lib,COMPILE_OPTIONS>)
+
+add_custom_command(TARGET drive PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:lib,INCLUDE_DIRECTORIES>
+                                   $<TARGET_PROPERTY:lib,COMPILE_DEFINITIONS>
+                                   $<TARGET_PROPERTY:lib,COMPILE_OPTIONS>)
diff --git a/Tests/RunCMake/GenEx-COMPILE_LANGUAGE/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-COMPILE_LANGUAGE/RunCMakeTest.cmake
index 6691fdf..15a5e79 100644
--- a/Tests/RunCMake/GenEx-COMPILE_LANGUAGE/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GenEx-COMPILE_LANGUAGE/RunCMakeTest.cmake
@@ -8,3 +8,4 @@
 run_cmake(COMPILE_LANGUAGE-add_library)
 run_cmake(COMPILE_LANGUAGE-add_test)
 run_cmake(COMPILE_LANGUAGE-unknown-lang)
+run_cmake(COMPILE_LANGUAGE-TARGET_PROPERTY)
diff --git a/Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-TARGET_PROPERTY.cmake b/Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-TARGET_PROPERTY.cmake
new file mode 100644
index 0000000..6a718d6
--- /dev/null
+++ b/Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/COMPILE_LANG_AND_ID-TARGET_PROPERTY.cmake
@@ -0,0 +1,17 @@
+enable_language(C)
+
+add_library (lib SHARED empty.c)
+set_target_properties(lib PROPERTIES
+  INCLUDE_DIRECTORIES "$<$<COMPILE_LANG_AND_ID:C,GNU>:/usr/include>"
+  COMPILE_DEFINITIONS "$<$<COMPILE_LANG_AND_ID:C,GNU>:DEF>"
+  COMPILE_OPTIONS "$<$<COMPILE_LANG_AND_ID:C,GNU>:-O>")
+
+add_custom_target(drive
+  COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:lib,INCLUDE_DIRECTORIES>
+                                   $<TARGET_PROPERTY:lib,COMPILE_DEFINITIONS>
+                                   $<TARGET_PROPERTY:lib,COMPILE_OPTIONS>)
+
+add_custom_command(TARGET drive PRE_BUILD
+  COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_PROPERTY:lib,INCLUDE_DIRECTORIES>
+                                   $<TARGET_PROPERTY:lib,COMPILE_DEFINITIONS>
+                                   $<TARGET_PROPERTY:lib,COMPILE_OPTIONS>)
diff --git a/Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/RunCMakeTest.cmake b/Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/RunCMakeTest.cmake
index a0a7bb9..68bd05d 100644
--- a/Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GenEx-COMPILE_LANG_AND_ID/RunCMakeTest.cmake
@@ -8,3 +8,4 @@
 run_cmake(COMPILE_LANG_AND_ID-add_library)
 run_cmake(COMPILE_LANG_AND_ID-add_test)
 run_cmake(COMPILE_LANG_AND_ID-unknown-lang)
+run_cmake(COMPILE_LANG_AND_ID-TARGET_PROPERTY)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES-check.cmake
new file mode 100644
index 0000000..ecf7bfe
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES-check.cmake
@@ -0,0 +1,17 @@
+file(READ "${RunCMake_TEST_BINARY_DIR}/out.txt" content)
+
+unset(RunCMake_TEST_FAILED)
+
+if (NOT content MATCHES "(INCLUDES1:${RunCMake_TEST_SOURCE_DIR}/include)")
+  string(APPEND RunCMake_TEST_FAILED "wrong content for INCLUDES1: \"${CMAKE_MATCH_1}\"\n")
+endif()
+
+if (NOT content MATCHES "(INCLUDES2:><)")
+  string(APPEND RunCMake_TEST_FAILED "wrong content for INCLUDES2: \"${CMAKE_MATCH_1}\"\n")
+endif()
+if (NOT content MATCHES "(INCLUDES3:><)")
+  string(APPEND RunCMake_TEST_FAILED "wrong content for INCLUDES3: \"${CMAKE_MATCH_1}\"\n")
+endif()
+if (NOT content MATCHES "(CUSTOM:>;;<)")
+  string(APPEND RunCMake_TEST_FAILED "wrong content for CUSTOM: \"${CMAKE_MATCH_1}\"\n")
+endif()
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake
index cb6f4d8..e9855be 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_PROPERTY-INCLUDE_DIRECTORIES.cmake
@@ -14,5 +14,10 @@
 add_library(foo4 STATIC empty.c)
 target_include_directories(foo4 PUBLIC $<TARGET_PROPERTY:foo3,INCLUDE_DIRECTORIES>)
 
+add_library (foo5 SHARED empty.c)
+set_property(TARGET foo5 PROPERTY INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CUDA>:/include/CUDA>" "$<$<COMPILE_LANGUAGE:Fortran>:/include/Fortran>")
+set_property(TARGET foo5 PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<$<COMPILE_LANGUAGE:CUDA>:/include/CUDA>" "$<$<COMPILE_LANGUAGE:Fortran>:/include/Fortran>")
+set_property(TARGET foo5 PROPERTY CUSTOM ";;")
+
 # Evaluate a genex that looks up INCLUDE_DIRECTORIES on multiple targets.
-file(GENERATE OUTPUT out.txt CONTENT "$<TARGET_PROPERTY:foo4,INCLUDE_DIRECTORIES>")
+file(GENERATE OUTPUT out.txt CONTENT "INCLUDES1:$<TARGET_PROPERTY:foo4,INCLUDE_DIRECTORIES>\nINCLUDES2:>$<TARGET_PROPERTY:foo5,INTERFACE_INCLUDE_DIRECTORIES><\nINCLUDES3:>$<TARGET_PROPERTY:foo5,INCLUDE_DIRECTORIES><\nCUSTOM:>$<TARGET_PROPERTY:foo5,CUSTOM><\n")
diff --git a/Tests/RunCMake/Graphviz/default_options-check.cmake b/Tests/RunCMake/Graphviz/default_options-check.cmake
index c9a7562..584e276 100644
--- a/Tests/RunCMake/Graphviz/default_options-check.cmake
+++ b/Tests/RunCMake/Graphviz/default_options-check.cmake
@@ -3,3 +3,11 @@
 ensure_files_match(
         ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_default_options.dot
         ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
+
+ensure_files_match(
+        ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_target_dependencies.dot.GraphicApplication
+        ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot.GraphicApplication)
+
+ensure_files_match(
+        ${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_target_dependers.dot.CompilerFlags.dependers
+        ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot.CompilerFlags.dependers)
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_target_dependencies.dot.GraphicApplication b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_target_dependencies.dot.GraphicApplication
new file mode 100644
index 0000000..92fe609
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_target_dependencies.dot.GraphicApplication
@@ -0,0 +1,26 @@
+digraph "GraphicApplication" {
+node [
+  fontsize = "12"
+];
+    "node6" [ label = "GraphicApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node6" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = "GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape = pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node4" [ label = "SystemLibrary", shape = octagon ];
+    "node2" -> "node4" [ style = dotted ] // CoreLibrary -> SystemLibrary
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node4" -> "node2" [ style = dotted ] // SystemLibrary -> CoreLibrary
+    "node7" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node8" [ label = "\"-lm\"", shape = septagon ];
+    "node7" -> "node8" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node7" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node7" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node9" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node7" -> "node9" [ style = dotted ] // GraphicLibrary -> GraphicLibraryObjects
+}
diff --git a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_target_dependers.dot.CompilerFlags.dependers b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_target_dependers.dot.CompilerFlags.dependers
new file mode 100644
index 0000000..82a2efe
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_target_dependers.dot.CompilerFlags.dependers
@@ -0,0 +1,30 @@
+digraph "CompilerFlags" {
+node [
+  fontsize = "12"
+];
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node4" [ label = "SystemLibrary", shape = octagon ];
+    "node4" -> "node2" [ style = dotted ] // SystemLibrary -> CoreLibrary
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node4" [ style = dotted ] // CoreLibrary -> SystemLibrary
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node6" [ label = "GraphicApplication", shape = egg ];
+    "node6" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node7" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node6" [ label = "GraphicApplication", shape = egg ];
+    "node6" -> "node7" [ style = dotted ] // GraphicApplication -> GraphicLibrary
+    "node10" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node11" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node11" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+    "node7" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node10" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> CompilerFlags
+    "node11" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node11" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> CompilerFlags
+}
diff --git a/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll-all-build-check.cmake b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll-all-build-check.cmake
new file mode 100644
index 0000000..a4d2758
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll-all-build-check.cmake
@@ -0,0 +1,9 @@
+check_files("${RunCMake_TEST_BINARY_DIR}"
+  INCLUDE
+    ${TARGET_FILE_release_only_tool_Release}
+    ${TARGET_EXE_FILE_release_only_tool_Release}
+
+  EXCLUDE
+    ${TARGET_FILE_release_only_tool_Debug}
+    ${TARGET_EXE_FILE_release_only_tool_Debug}
+  )
diff --git a/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake
new file mode 100644
index 0000000..52f84ea
--- /dev/null
+++ b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake
@@ -0,0 +1,12 @@
+enable_language(C)
+
+set(CMAKE_CONFIGURATION_TYPES "Release;Debug" CACHE STRING "")
+set(CMAKE_DEFAULT_BUILD_TYPE "Release" CACHE STRING "")
+set(CMAKE_CROSS_CONFIGS "all" CACHE STRING "")
+set(CMAKE_DEFAULT_CONFIGS "all" CACHE STRING "")
+
+add_executable(release_only_tool main.c)
+set_property(TARGET release_only_tool PROPERTY EXCLUDE_FROM_ALL "$<NOT:$<CONFIG:Release>>")
+
+include(${CMAKE_CURRENT_LIST_DIR}/Common.cmake)
+generate_output_files(release_only_tool)
diff --git a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
index 76b488e..9249724 100644
--- a/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/RunCMakeTest.cmake
@@ -274,6 +274,11 @@
 file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}/install")
 run_ninja(Install all-install build.ninja install:all)
 
+set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ExcludeFromAll-build)
+run_cmake_configure(ExcludeFromAll)
+include(${RunCMake_TEST_BINARY_DIR}/target_files.cmake)
+run_cmake_build(ExcludeFromAll all "" all:all)
+
 # FIXME Get this working
 #set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/AutoMocExecutable-build)
 #run_cmake_configure(AutoMocExecutable)
diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index cb20fb1..c13c694 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -154,6 +154,7 @@
 
     "|[^\n]*xcodebuild[^\n]*warning: file type[^\n]*is based on missing file type"
     "|[^\n]*is a member of multiple groups"
+    "|[^\n]*offset in archive not a multiple of 8"
     "|[^\n]*from Time Machine by path"
     "|[^\n]*Bullseye Testing Technology"
     ")[^\n]*\n)+"
diff --git a/Tests/RunCMake/alias_targets/get_property-subdir/CMakeLists.txt b/Tests/RunCMake/alias_targets/get_property-subdir/CMakeLists.txt
index bfd9840..b114b75 100644
--- a/Tests/RunCMake/alias_targets/get_property-subdir/CMakeLists.txt
+++ b/Tests/RunCMake/alias_targets/get_property-subdir/CMakeLists.txt
@@ -6,3 +6,10 @@
 check_property (alias::import-local-subdir IMPORTED "TRUE")
 check_property (alias::import-local-subdir ALIAS_GLOBAL "FALSE")
 check_property (alias::import-local-subdir IMPORT_LOCAL_PROPERTY "IMPORT_LOCAL")
+
+
+# non-global alias defined in parent directory must be visible in sub-directory
+check_property (alias::import-local ALIASED_TARGET "import-local")
+check_property (alias::import-local IMPORTED "TRUE")
+check_property (alias::import-local ALIAS_GLOBAL "FALSE")
+check_property (alias::import-local IMPORT_LOCAL_PROPERTY "IMPORT_LOCAL")
diff --git a/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-result.txt b/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-stderr.txt b/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-stderr.txt
new file mode 100644
index 0000000..31dedd2
--- /dev/null
+++ b/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-stderr.txt
@@ -0,0 +1 @@
+Defect count: 20
diff --git a/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-stdout.txt b/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-stdout.txt
new file mode 100644
index 0000000..aa3e698
--- /dev/null
+++ b/Tests/RunCMake/ctest_memcheck/DummyCudaMemcheck-stdout.txt
@@ -0,0 +1,10 @@
+Memory checking results:
+Uninitialized __global__ memory read - 1
+Unused memory - 1
+Barrier error - 2
+Invalid __global__ read - 1
+cudaErrorLaunchFailure - 2
+Memory leak - 1
+Potential WAR hazard detected - 4
+Potential RAW hazard detected - 4
+Race reported - 4
diff --git a/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake b/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake
index ab4c5ab..2b3165b 100644
--- a/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_memcheck/RunCMakeTest.cmake
@@ -175,3 +175,15 @@
 unset(CTEST_EXTRA_CODE)
 unset(CTEST_MEMCHECK_ARGS)
 unset(CTEST_SUFFIX_CODE)
+
+#-----------------------------------------------------------------------------
+set(CMAKELISTS_EXTRA_CODE
+"add_test(NAME TestSan COMMAND \"${CMAKE_COMMAND}\"
+-P \"${RunCMake_SOURCE_DIR}/testCudaMemcheck.cmake\")
+")
+set(CTEST_SUFFIX_CODE "message(\"Defect count: \${defect_count}\")")
+set(CTEST_MEMCHECK_ARGS "DEFECT_COUNT defect_count")
+run_mc_test(DummyCudaMemcheck "${PSEUDO_CUDA_MEMCHECK}")
+unset(CTEST_MEMCHECK_ARGS)
+unset(CTEST_SUFFIX_CODE)
+unset(CTEST_EXTRA_CODE)
diff --git a/Tests/RunCMake/ctest_memcheck/testCudaMemcheck.cmake b/Tests/RunCMake/ctest_memcheck/testCudaMemcheck.cmake
new file mode 100644
index 0000000..d7d8213
--- /dev/null
+++ b/Tests/RunCMake/ctest_memcheck/testCudaMemcheck.cmake
@@ -0,0 +1,264 @@
+# this file simulates an execution of cuda-memcheck
+
+set(LOG_FILE "$ENV{PSEUDO_LOGFILE}")
+message("LOG_FILE=[${LOG_FILE}]")
+
+# clear the log file
+file(REMOVE "${LOG_FILE}")
+
+# create an error of each type of sanitizer tool and failure
+
+# initcheck
+file(APPEND "${LOG_FILE}"
+"========= CUDA-MEMCHECK
+========= Uninitialized __global__ memory read of size 4
+=========     at 0x00000020 in test(int*, int*)
+=========     by thread (0,0,0) in block (0,0,0)
+=========     Address 0x1303d80000
+=========     Saved host backtrace up to driver entry point
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./uninit-read [0x101d9]
+=========     Host Frame:./uninit-read [0x10267]
+=========     Host Frame:./uninit-read [0x465b5]
+=========     Host Frame:./uninit-read [0x3342]
+=========     Host Frame:./uninit-read [0x3143]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./uninit-read [0x31e2]
+=========
+========= Unused memory in allocation 0x1303d80000 of size 16 bytes
+=========     Not written any memory.
+=========     100.00% of allocation were unused.
+=========     Saved host backtrace up to driver entry point
+=========     Host Frame:/lib64/libcuda.so.1 (cuMemAlloc_v2 + 0x1b7) [0x26ec97]
+=========     Host Frame:./uninit-read [0x2bbd3]
+=========     Host Frame:./uninit-read [0x71ab]
+=========     Host Frame:./uninit-read [0x3c84f]
+=========     Host Frame:./uninit-read [0x3111]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./uninit-read [0x31e2]
+=========
+========= ERROR SUMMARY: 2 errors
+")
+
+
+# synccheck
+file(APPEND "${LOG_FILE}"
+"========= CUDA-MEMCHECK
+========= Barrier error detected. Divergent thread(s) in warp
+=========     at 0x00000058 in test(int*, int*)
+=========     by thread (1,0,0) in block (0,0,0)
+=========     Device Frame:test(int*, int*) (test(int*, int*) : 0x60)
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./sync [0x101d9]
+=========     Host Frame:./sync [0x10267]
+=========     Host Frame:./sync [0x465b5]
+=========     Host Frame:./sync [0x3342]
+=========     Host Frame:./sync [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./sync [0x31e2]
+=========
+========= Barrier error detected. Divergent thread(s) in warp
+=========     at 0x00000058 in test(int*, int*)
+=========     by thread (0,0,0) in block (0,0,0)
+=========     Device Frame:test(int*, int*) (test(int*, int*) : 0x60)
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./sync [0x101d9]
+=========     Host Frame:./sync [0x10267]
+=========     Host Frame:./sync [0x465b5]
+=========     Host Frame:./sync [0x3342]
+=========     Host Frame:./sync [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./sync [0x31e2]
+=========
+========= ERROR SUMMARY: 2 errors
+")
+
+# memcheck
+file(APPEND "${LOG_FILE}"
+"========= CUDA-MEMCHECK
+========= Invalid __global__ read of size 4
+=========     at 0x00000020 in test(int*, int*)
+=========     by thread (0,0,0) in block (0,0,0)
+=========     Address 0x00000000 is out of bounds
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./invalid-read [0x101d9]
+=========     Host Frame:./invalid-read [0x10267]
+=========     Host Frame:./invalid-read [0x465b5]
+=========     Host Frame:./invalid-read [0x3342]
+=========     Host Frame:./invalid-read [0x3142]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./invalid-read [0x31e2]
+=========
+========= Program hit cudaErrorLaunchFailure (error 719) due to \"unspecified launch failure\" on CUDA API call to cudaDeviceSynchronize.
+=========     Saved host backtrace up to driver entry point at error
+=========     Host Frame:/lib64/libcuda.so.1 [0x3ac5a3]
+=========     Host Frame:./invalid-read [0x2e576]
+=========     Host Frame:./invalid-read [0x3147]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./invalid-read [0x31e2]
+=========
+========= Program hit cudaErrorLaunchFailure (error 719) due to \"unspecified launch failure\" on CUDA API call to cudaFree.
+=========     Saved host backtrace up to driver entry point at error
+=========     Host Frame:/lib64/libcuda.so.1 [0x3ac5a3]
+=========     Host Frame:./invalid-read [0x3c106]
+=========     Host Frame:./invalid-read [0x3150]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./invalid-read [0x31e2]
+=========
+========= LEAK SUMMARY: 0 bytes leaked in 0 allocations
+========= ERROR SUMMARY: 3 errors
+")
+
+# memcheck with leak-check full
+file(APPEND "${LOG_FILE}"
+"========= CUDA-MEMCHECK
+========= Leaked 10 bytes at 0x1303d80000
+=========     Saved host backtrace up to driver entry point at cudaMalloc time
+=========     Host Frame:/lib64/libcuda.so.1 (cuMemAlloc_v2 + 0x1b7) [0x26ec97]
+=========     Host Frame:./leak [0x2bab3]
+=========     Host Frame:./leak [0x708b]
+=========     Host Frame:./leak [0x3c72f]
+=========     Host Frame:./leak [0x3113]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./leak [0x3174]
+=========
+========= LEAK SUMMARY: 10 bytes leaked in 1 allocations
+========= ERROR SUMMARY: 1 error
+")
+
+# racecheck with racecheck-report all
+file(APPEND "${LOG_FILE}"
+"========= CUDA-MEMCHECK
+========= WARN:(Warp Level Programming) Potential WAR hazard detected at __shared__ 0x3 in block (0, 0, 0) :
+=========     Read Thread (31, 0, 0) at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     Write Thread (0, 0, 0) at 0x000001a8 in ./race.cu:4:test(int*, int*)
+=========     Current Value : 0, Incoming Value : 0
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./race [0x101d9]
+=========     Host Frame:./race [0x10267]
+=========     Host Frame:./race [0x465b5]
+=========     Host Frame:./race [0x3342]
+=========     Host Frame:./race [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./race [0x31e2]
+=========
+========= WARN:(Warp Level Programming) Potential WAR hazard detected at __shared__ 0x2 in block (0, 0, 0) :
+=========     Read Thread (31, 0, 0) at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     Write Thread (0, 0, 0) at 0x000001a8 in ./race.cu:4:test(int*, int*)
+=========     Current Value : 0, Incoming Value : 0
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./race [0x101d9]
+=========     Host Frame:./race [0x10267]
+=========     Host Frame:./race [0x465b5]
+=========     Host Frame:./race [0x3342]
+=========     Host Frame:./race [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./race [0x31e2]
+=========
+========= WARN:(Warp Level Programming) Potential WAR hazard detected at __shared__ 0x1 in block (0, 0, 0) :
+=========     Read Thread (31, 0, 0) at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     Write Thread (0, 0, 0) at 0x000001a8 in ./race.cu:4:test(int*, int*)
+=========     Current Value : 0, Incoming Value : 0
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./race [0x101d9]
+=========     Host Frame:./race [0x10267]
+=========     Host Frame:./race [0x465b5]
+=========     Host Frame:./race [0x3342]
+=========     Host Frame:./race [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./race [0x31e2]
+=========
+========= WARN:(Warp Level Programming) Potential WAR hazard detected at __shared__ 0x0 in block (0, 0, 0) :
+=========     Read Thread (31, 0, 0) at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     Write Thread (0, 0, 0) at 0x000001a8 in ./race.cu:4:test(int*, int*)
+=========     Current Value : 0, Incoming Value : 1
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./race [0x101d9]
+=========     Host Frame:./race [0x10267]
+=========     Host Frame:./race [0x465b5]
+=========     Host Frame:./race [0x3342]
+=========     Host Frame:./race [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./race [0x31e2]
+=========
+========= WARN:(Warp Level Programming) Potential RAW hazard detected at __shared__ 0x3 in block (0, 0, 0) :
+=========     Write Thread (31, 0, 0) at 0x00000148 in ./race.cu:3:test(int*, int*)
+=========     Read Thread (0, 0, 0) at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     Current Value : 0
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./race [0x101d9]
+=========     Host Frame:./race [0x10267]
+=========     Host Frame:./race [0x465b5]
+=========     Host Frame:./race [0x3342]
+=========     Host Frame:./race [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./race [0x31e2]
+=========
+========= WARN:(Warp Level Programming) Potential RAW hazard detected at __shared__ 0x2 in block (0, 0, 0) :
+=========     Write Thread (31, 0, 0) at 0x00000148 in ./race.cu:3:test(int*, int*)
+=========     Read Thread (0, 0, 0) at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     Current Value : 0
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./race [0x101d9]
+=========     Host Frame:./race [0x10267]
+=========     Host Frame:./race [0x465b5]
+=========     Host Frame:./race [0x3342]
+=========     Host Frame:./race [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./race [0x31e2]
+=========
+========= WARN:(Warp Level Programming) Potential RAW hazard detected at __shared__ 0x1 in block (0, 0, 0) :
+=========     Write Thread (31, 0, 0) at 0x00000148 in ./race.cu:3:test(int*, int*)
+=========     Read Thread (0, 0, 0) at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     Current Value : 0
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./race [0x101d9]
+=========     Host Frame:./race [0x10267]
+=========     Host Frame:./race [0x465b5]
+=========     Host Frame:./race [0x3342]
+=========     Host Frame:./race [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./race [0x31e2]
+=========
+========= WARN:(Warp Level Programming) Potential RAW hazard detected at __shared__ 0x0 in block (0, 0, 0) :
+=========     Write Thread (31, 0, 0) at 0x00000148 in ./race.cu:3:test(int*, int*)
+=========     Read Thread (0, 0, 0) at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     Current Value : 0
+=========     Saved host backtrace up to driver entry point at kernel launch time
+=========     Host Frame:/lib64/libcuda.so.1 (cuLaunchKernel + 0x346) [0x297db6]
+=========     Host Frame:./race [0x101d9]
+=========     Host Frame:./race [0x10267]
+=========     Host Frame:./race [0x465b5]
+=========     Host Frame:./race [0x3342]
+=========     Host Frame:./race [0x314a]
+=========     Host Frame:/lib64/libc.so.6 (__libc_start_main + 0xf5) [0x22505]
+=========     Host Frame:./race [0x31e2]
+=========
+========= WARN: Race reported between Read access at 0x00000170 in ./race.cu:4:test(int*, int*)
+=========     and Write access at 0x00000148 in ./race.cu:3:test(int*, int*) [4 hazards]
+=========     and Write access at 0x000001a8 in ./race.cu:4:test(int*, int*) [4 hazards]
+=========
+========= WARN: Race reported between Write access at 0x00000148 in ./race.cu:3:test(int*, int*)
+=========     and Write access at 0x00000148 in ./race.cu:3:test(int*, int*) [124 hazards]
+=========     and Read access at 0x00000170 in ./race.cu:4:test(int*, int*) [4 hazards]
+=========
+========= WARN: Race reported between Write access at 0x000001a8 in ./race.cu:4:test(int*, int*)
+=========     and Write access at 0x000001a8 in ./race.cu:4:test(int*, int*) [124 hazards]
+=========     and Read access at 0x00000170 in ./race.cu:4:test(int*, int*) [4 hazards]
+=========
+========= WARN: Race reported between Write access at 0x00000148 in ./race.cu:3:test(int*, int*)
+=========     and Write access at 0x00000148 in ./race.cu:3:test(int*, int*) [124 hazards]
+=========     and Read access at 0x00000170 in ./race.cu:4:test(int*, int*) [4 hazards]
+=========
+========= RACECHECK SUMMARY: 12 hazards displayed (0 errors, 12 warnings)
+")
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake
index 7f68398..e6f2623 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-all-check.cmake
@@ -16,7 +16,15 @@
   endif()
 endfunction()
 
-set(_check
+function(set_with_libsystem var)
+  set(_tmp "${ARGN}")
+  if(EXISTS "/usr/lib/libSystem.B.dylib")
+    list(APPEND _tmp [[/usr/lib/libSystem\.B\.dylib]])
+  endif()
+  set("${var}" "${_tmp}" PARENT_SCOPE)
+endfunction()
+
+set_with_libsystem(_check
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/bin/../lib/executable_path/libexecutable_path\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/bin/../lib/rpath_executable_path/librpath_executable_path\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/libtestlib\.dylib]]
@@ -24,7 +32,6 @@
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
-  [[/usr/lib/libSystem\.B\.dylib]]
   )
 check_contents(deps/deps1.txt "^${_check}$")
 
@@ -37,13 +44,12 @@
   )
 check_contents(deps/udeps1.txt "^${_check}$")
 
-set(_check
+set_with_libsystem(_check
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/libtestlib\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
-  [[/usr/lib/libSystem\.B\.dylib]]
   )
 check_contents(deps/deps2.txt "^${_check}$")
 
@@ -60,13 +66,12 @@
   )
 check_contents(deps/udeps2.txt "^${_check}$")
 
-set(_check
+set_with_libsystem(_check
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/libtestlib\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
-  [[/usr/lib/libSystem\.B\.dylib]]
   )
 check_contents(deps/deps3.txt "^${_check}$")
 
@@ -83,7 +88,7 @@
   )
 check_contents(deps/udeps3.txt "^${_check}$")
 
-set(_check
+set_with_libsystem(_check
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/bin/../lib/executable_path/libexecutable_path\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/bin/../lib/rpath_executable_path/librpath_executable_path\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/libtestlib\.dylib]]
@@ -91,7 +96,6 @@
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
-  [[/usr/lib/libSystem\.B\.dylib]]
   )
 check_contents(deps/deps4.txt "^${_check}$")
 
@@ -104,14 +108,13 @@
   )
 check_contents(deps/udeps4.txt "^${_check}$")
 
-set(_check
+set_with_libsystem(_check
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/bundle_executable/bin/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/libtestlib\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
-  [[/usr/lib/libSystem\.B\.dylib]]
   )
 check_contents(deps/deps5.txt "^${_check}$")
 
@@ -125,14 +128,13 @@
   )
 check_contents(deps/udeps5.txt "^${_check}$")
 
-set(_check
+set_with_libsystem(_check
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/bundle_executable/bin/../lib/executable_path_bundle/libexecutable_path_bundle\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/libtestlib\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/loader_path/libloader_path\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/../rpath/librpath\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/normal/libnormal\.dylib]]
   [[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-build/root-all/executable/lib/rpath_loader_path/librpath_loader_path\.dylib]]
-  [[/usr/lib/libSystem\.B\.dylib]]
   )
 check_contents(deps/deps6.txt "^${_check}$")
 
diff --git a/Tests/RunCMake/target_link_libraries-ALIAS/AliasTargets.cmake b/Tests/RunCMake/target_link_libraries-ALIAS/AliasTargets.cmake
index 73f8a7d..316b74b 100644
--- a/Tests/RunCMake/target_link_libraries-ALIAS/AliasTargets.cmake
+++ b/Tests/RunCMake/target_link_libraries-ALIAS/AliasTargets.cmake
@@ -15,22 +15,25 @@
 add_library(import-local SHARED IMPORTED)
 set_property(TARGET import-local PROPERTY IMPORTED_LOCATION "${binary_dir}/${CMAKE_STATIC_LIBRARY_PREFIX}func${CMAKE_SHARED_LIBRARY_SUFFIX}")
 set_property(TARGET import-local PROPERTY IMPORTED_IMPLIB "${binary_dir}/${CMAKE_STATIC_LIBRARY_PREFIX}func${CMAKE_IMPORT_LIBRARY_SUFFIX}")
-add_library(alias-local ALIAS import-local)
+add_library(alias::local ALIAS import-local)
 
 add_library (lib-local SHARED lib.c)
-target_link_libraries (lib-local PRIVATE import-local)
+target_link_libraries (lib-local PRIVATE alias::local)
 
 add_executable (main-local main.c)
-target_link_libraries (main-local PRIVATE import-local)
+target_link_libraries (main-local PRIVATE alias::local)
 
 
 add_library(import-global SHARED IMPORTED GLOBAL)
 set_property(TARGET import-global PROPERTY IMPORTED_LOCATION "${binary_dir}/${CMAKE_STATIC_LIBRARY_PREFIX}func${CMAKE_SHARED_LIBRARY_SUFFIX}")
 set_property(TARGET import-global PROPERTY IMPORTED_IMPLIB "${binary_dir}/${CMAKE_STATIC_LIBRARY_PREFIX}func${CMAKE_IMPORT_LIBRARY_SUFFIX}")
-add_library(alias-global ALIAS import-global)
+add_library(alias::global ALIAS import-global)
 
 add_library (lib-global SHARED lib.c)
-target_link_libraries (lib-global PRIVATE import-global)
+target_link_libraries (lib-global PRIVATE alias::global)
 
 add_executable (main-global main.c)
-target_link_libraries (main-global PRIVATE import-global)
+target_link_libraries (main-global PRIVATE alias::global)
+
+
+add_subdirectory(sub_dir)
diff --git a/Tests/RunCMake/target_link_libraries-ALIAS/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries-ALIAS/RunCMakeTest.cmake
index 4d24a6e..42ec47e 100644
--- a/Tests/RunCMake/target_link_libraries-ALIAS/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_libraries-ALIAS/RunCMakeTest.cmake
@@ -19,5 +19,7 @@
 run_cmake_target(AliasTargets main-local main-local --config Release)
 run_cmake_target(AliasTargets lib-global lib-global --config Release)
 run_cmake_target(AliasTargets main-global main-global --config Release)
+run_cmake_target(AliasTargets lib-sub lib-sub --config Release)
+run_cmake_target(AliasTargets main-sub main-sub --config Release)
 unset(RunCMake_TEST_OPTIONS)
 unset(RunCMake_TEST_OUTPUT_MERGE)
diff --git a/Tests/RunCMake/target_link_libraries-ALIAS/sub_dir/CMakeLists.txt b/Tests/RunCMake/target_link_libraries-ALIAS/sub_dir/CMakeLists.txt
new file mode 100644
index 0000000..326e964
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries-ALIAS/sub_dir/CMakeLists.txt
@@ -0,0 +1,7 @@
+
+
+add_library (lib-sub SHARED ../lib.c)
+target_link_libraries (lib-sub PRIVATE alias::local)
+
+add_executable (main-sub ../main.c)
+target_link_libraries (main-sub PRIVATE alias::local)
diff --git a/Tests/RunCMake/try_compile/CudaStandard-stderr.txt b/Tests/RunCMake/try_compile/CudaStandard-stderr.txt
index 3c6bdf6..bcf95d5 100644
--- a/Tests/RunCMake/try_compile/CudaStandard-stderr.txt
+++ b/Tests/RunCMake/try_compile/CudaStandard-stderr.txt
@@ -1,5 +1,5 @@
 ^CMake Error at .*/Tests/RunCMake/try_compile/CudaStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\):
-  CUDA_STANDARD is set to invalid value '3'
+  CUDA_STANDARD is set to invalid value '4'
 +
 CMake Error at CudaStandard.cmake:[0-9]+ \(try_compile\):
   Failed to generate test project build system.
diff --git a/Tests/RunCMake/try_compile/CudaStandard.cmake b/Tests/RunCMake/try_compile/CudaStandard.cmake
index 96da422..a230424 100644
--- a/Tests/RunCMake/try_compile/CudaStandard.cmake
+++ b/Tests/RunCMake/try_compile/CudaStandard.cmake
@@ -1,7 +1,7 @@
 enable_language(CUDA)
 try_compile(result ${CMAKE_CURRENT_BINARY_DIR}
   SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.cu
-  CUDA_STANDARD 3
+  CUDA_STANDARD 4
   OUTPUT_VARIABLE out
   )
 message("try_compile output:\n${out}")
diff --git a/Tests/SwiftOnly/CMakeLists.txt b/Tests/SwiftOnly/CMakeLists.txt
index e24279b..41d14ea 100644
--- a/Tests/SwiftOnly/CMakeLists.txt
+++ b/Tests/SwiftOnly/CMakeLists.txt
@@ -35,3 +35,4 @@
 
 # Dummy to make sure generation works with such targets.
 add_library(SwiftIface INTERFACE)
+target_link_libraries(SwiftOnly PRIVATE SwiftIface)
diff --git a/Utilities/std/CMakeLists.txt b/Utilities/std/CMakeLists.txt
index 17a7aaa..23d9104 100644
--- a/Utilities/std/CMakeLists.txt
+++ b/Utilities/std/CMakeLists.txt
@@ -4,7 +4,9 @@
 set(CMAKE_CXX_EXTENSIONS FALSE)
 
 # source files for CMake std library
-set(SRCS cm/bits/string_view.cxx
+set(SRCS cm/bits/fs_path.cxx
+         cm/bits/string_view.cxx
+         cm/filesystem
          cm/memory
          cm/optional
          cm/shared_mutex
diff --git a/Utilities/std/cm/bits/fs_path.cxx b/Utilities/std/cm/bits/fs_path.cxx
new file mode 100644
index 0000000..b8c5631
--- /dev/null
+++ b/Utilities/std/cm/bits/fs_path.cxx
@@ -0,0 +1,1029 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#include <cm/filesystem> // IWYU pragma: associated
+
+#if !defined(CMake_HAVE_CXX_FILESYSTEM)
+
+#  include <algorithm>
+#  include <cassert>
+#  include <cstddef>
+#  include <cstdlib>
+#  include <functional>
+#  include <string>
+#  include <utility>
+#  include <vector>
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+#    include <cctype>
+#  endif
+#  if defined(_WIN32) || defined(__CYGWIN__)
+#    include <iterator>
+#  endif
+
+#  include <cm/memory>
+#  include <cm/string_view>
+#  include <cmext/string_view>
+
+namespace cm {
+namespace filesystem {
+namespace internals {
+
+class path_parser
+{
+#  if defined(__SUNPRO_CC) && defined(__sparc)
+  // Oracle DeveloperStudio C++ compiler generates wrong code if enum size
+  // is different than the default.
+  using enum_size = int;
+#  else
+  using enum_size = unsigned char;
+#  endif
+
+  enum class state : enum_size
+  {
+    before_begin,
+    in_root_name,
+    in_root_dir,
+    in_filename,
+    trailing_separator,
+    at_end
+  };
+
+  using pointer = char const*;
+
+public:
+  enum class seek_position : enum_size
+  {
+    root_name = static_cast<enum_size>(state::in_root_name),
+    root_directory = static_cast<enum_size>(state::in_root_dir)
+  };
+  enum class peek_fragment : enum_size
+  {
+    remainder,
+    path
+  };
+
+  path_parser(cm::string_view path, bool set_at_end = false)
+    : State(set_at_end ? state::at_end : state::before_begin)
+    , Path(path)
+  {
+  }
+
+  path_parser(const path_parser&) = default;
+
+  ~path_parser() = default;
+
+  void reset() noexcept { this->set_state(state::before_begin); }
+
+  void increment() noexcept
+  {
+    const pointer start = this->next_token();
+    const pointer end = this->after_end();
+
+    if (start == end) {
+      this->set_state(state::at_end);
+      return;
+    }
+
+    switch (this->State) {
+      case state::before_begin: {
+        auto pos = this->consume_root_name(start, end);
+        if (pos) {
+          this->set_state(state::in_root_name);
+        } else {
+          pos = this->consume_separator(start, end);
+          if (pos) {
+            this->set_state(state::in_root_dir);
+          } else {
+            this->consume_filename(start, end);
+            this->set_state(state::in_filename);
+          }
+        }
+        break;
+      }
+      case state::in_root_name: {
+        auto pos = this->consume_separator(start, end);
+        if (pos) {
+          this->set_state(state::in_root_dir);
+        } else {
+          this->consume_filename(start, end);
+          this->set_state(state::in_filename);
+        }
+        break;
+      }
+      case state::in_root_dir: {
+        this->consume_filename(start, end);
+        this->set_state(state::in_filename);
+        break;
+      }
+      case state::in_filename: {
+        auto posSep = this->consume_separator(start, end);
+        if (posSep != end) {
+          auto pos = this->consume_filename(posSep, end);
+          if (pos) {
+            return;
+          }
+        }
+        set_state(state::trailing_separator);
+        break;
+      }
+      case state::trailing_separator: {
+        this->set_state(state::at_end);
+        break;
+      }
+      case state::at_end:
+        // unreachable
+        std::abort();
+    }
+  }
+
+  void decrement() noexcept
+  {
+    const pointer rstart = this->current_token() - 1;
+    const pointer rend = this->before_start();
+
+    if (rstart == rend) {
+      this->set_state(state::before_begin);
+      return;
+    }
+
+    switch (this->State) {
+      case state::at_end: {
+        auto posSep = this->consume_separator(rstart, rend);
+        if (posSep) {
+          if (posSep == rend) {
+            this->set_state(state::in_root_dir);
+          } else {
+            auto pos = this->consume_root_name(posSep, rend, true);
+            if (pos == rend) {
+              this->set_state(state::in_root_dir);
+            } else {
+              this->set_state(state::trailing_separator);
+            }
+          }
+        } else {
+          auto pos = this->consume_root_name(rstart, rend);
+          if (pos == rend) {
+            this->set_state(state::in_root_name);
+          } else {
+            this->consume_filename(rstart, rend);
+            this->set_state(state::in_filename);
+          }
+        }
+        break;
+      }
+      case state::trailing_separator: {
+        this->consume_filename(rstart, rend);
+        this->set_state(state::in_filename);
+        break;
+      }
+      case state::in_filename: {
+        auto posSep = this->consume_separator(rstart, rend);
+        if (posSep == rend) {
+          this->set_state(state::in_root_dir);
+        } else {
+          auto pos = this->consume_root_name(posSep, rend, true);
+          if (pos == rend) {
+            this->set_state(state::in_root_dir);
+          } else {
+            this->consume_filename(posSep, rend);
+            this->set_state(state::in_filename);
+          }
+        }
+        break;
+      }
+      case state::in_root_dir: {
+        auto pos = this->consume_root_name(rstart, rend);
+        if (pos) {
+          this->set_state(state::in_root_name);
+        }
+        break;
+      }
+      case state::in_root_name:
+      case state::before_begin: {
+        // unreachable
+        std::abort();
+      }
+    }
+  }
+
+  path_parser& operator++() noexcept
+  {
+    this->increment();
+    return *this;
+  }
+
+  path_parser& operator--() noexcept
+  {
+    this->decrement();
+    return *this;
+  }
+
+  cm::string_view operator*() const noexcept
+  {
+    switch (this->State) {
+      case state::before_begin:
+      case state::at_end:
+        return cm::string_view();
+      case state::trailing_separator:
+        return "";
+      case state::in_root_dir:
+      case state::in_root_name:
+      case state::in_filename:
+        return this->Entry;
+      default:
+        // unreachable
+        std::abort();
+    }
+  }
+
+  void seek(seek_position position)
+  {
+    state s = static_cast<state>(static_cast<int>(position));
+
+    while (this->State <= s) {
+      this->increment();
+    }
+  }
+
+  cm::string_view peek(peek_fragment fragment)
+  {
+    if (fragment == peek_fragment::remainder) {
+      // peek-up remain part of the initial path
+      return { this->Entry.data(),
+               std::size_t(&this->Path.back() - this->Entry.data() + 1) };
+    }
+    if (fragment == peek_fragment::path) {
+      // peek-up full path until current position
+      return { this->Path.data(),
+               std::size_t(&this->Entry.back() - this->Path.data() + 1) };
+    }
+    return {};
+  }
+
+  bool in_root_name() const { return this->State == state::in_root_name; }
+  bool in_root_directory() const { return this->State == state::in_root_dir; }
+  bool at_end() const { return this->State == state::at_end; }
+
+  bool at_start() const { return this->Entry.data() == this->Path.data(); }
+
+private:
+  void set_state(state newState) noexcept
+  {
+    this->State = newState;
+    if (newState == state::before_begin || newState == state::at_end) {
+      this->Entry = {};
+    }
+  }
+
+  pointer before_start() const noexcept { return this->Path.data() - 1; }
+  pointer after_end() const noexcept
+  {
+    return this->Path.data() + this->Path.size();
+  }
+
+  pointer current_token() const noexcept
+  {
+    switch (this->State) {
+      case state::before_begin:
+      case state::in_root_name:
+        return &this->Path.front();
+      case state::in_root_dir:
+      case state::in_filename:
+      case state::trailing_separator:
+        return &this->Entry.front();
+      case state::at_end:
+        return &this->Path.back() + 1;
+      default:
+        // unreachable
+        std::abort();
+    }
+  }
+  pointer next_token() const noexcept
+  {
+    switch (this->State) {
+      case state::before_begin:
+        return this->Path.data();
+      case state::in_root_name:
+      case state::in_root_dir:
+      case state::in_filename:
+        return &this->Entry.back() + 1;
+      case state::trailing_separator:
+      case state::at_end:
+        return after_end();
+      default:
+        // unreachable
+        std::abort();
+    }
+  }
+
+  pointer consume_separator(pointer ptr, pointer end) noexcept
+  {
+    if (ptr == end ||
+        (*ptr != '/'
+#  if defined(_WIN32)
+         && *ptr != '\\'
+#  endif
+         )) {
+      return nullptr;
+    }
+    const auto step = ptr < end ? 1 : -1;
+    ptr += step;
+    while (ptr != end &&
+           (*ptr == '/'
+#  if defined(_WIN32)
+            || *ptr == ' \\'
+#  endif
+            )) {
+      ptr += step;
+    }
+    if (step == 1) {
+      this->Entry = cm::string_view(ptr - 1, 1);
+    } else {
+      this->Entry = cm::string_view(ptr + 1, 1);
+    }
+
+    return ptr;
+  }
+
+  pointer consume_filename(pointer ptr, pointer end) noexcept
+  {
+    auto start = ptr;
+
+    if (ptr == end || *ptr == '/'
+#  if defined(_WIN32)
+        || *ptr == '\\'
+#  endif
+    ) {
+      return nullptr;
+    }
+    const auto step = ptr < end ? 1 : -1;
+    ptr += step;
+    while (ptr != end && *ptr != '/'
+#  if defined(_WIN32)
+           && *ptr != '\\'
+#  endif
+    ) {
+      ptr += step;
+    }
+
+#  if defined(_WIN32)
+    if (step == -1 && (start - ptr) >= 2 && ptr == end) {
+      // rollback drive name consumption, if any
+      if (this->is_drive_name(ptr + 1)) {
+        ptr += 2;
+      }
+      if (ptr == start) {
+        return nullptr;
+      }
+    }
+#  endif
+
+    if (step == 1) {
+      this->Entry = cm::string_view(start, ptr - start);
+    } else {
+      this->Entry = cm::string_view(ptr + 1, start - ptr);
+    }
+
+    return ptr;
+  }
+
+#  if defined(_WIN32)
+  bool is_drive_name(pointer ptr)
+  {
+    return std::toupper(ptr[0]) >= 'A' && std::toupper(ptr[0]) <= 'Z' &&
+      ptr[1] == ':';
+  }
+#  endif
+
+  pointer consume_root_name(pointer ptr, pointer end,
+                            bool check_only = false) noexcept
+  {
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+    if (ptr < end) {
+      if ((end - ptr) >= 2 && this->is_drive_name(ptr)) {
+        // Drive letter (X:) is a root name
+        if (!check_only) {
+          this->Entry = cm::string_view(ptr, 2);
+        }
+        return ptr + 2;
+      }
+      if ((end - ptr) > 2 && (ptr[0] == '/' || ptr[0] == '\\') &&
+          (ptr[1] == '/' || ptr[1] == '\\') &&
+          (ptr[2] != '/' && ptr[2] != '\\')) {
+        // server name (//server) is a root name
+        auto pos = std::find_if(ptr + 2, end,
+                                [](char c) { return c == '/' || c == '\\'; });
+        if (!check_only) {
+          this->Entry = cm::string_view(ptr, pos - ptr);
+        }
+        return pos;
+      }
+    } else {
+      if ((ptr - end) >= 2 && this->is_drive_name(ptr - 1)) {
+        // Drive letter (X:) is a root name
+        if (!check_only) {
+          this->Entry = cm::string_view(ptr - 1, 2);
+        }
+        return ptr - 2;
+      }
+      if ((ptr - end) > 2 && (ptr[0] != '/' && ptr[0] != '\\')) {
+        std::reverse_iterator<pointer> start(ptr);
+        std::reverse_iterator<pointer> stop(end);
+        auto res = std::find_if(start, stop,
+                                [](char c) { return c == '/' || c == '\\'; });
+        pointer pos = res.base() - 1;
+        if ((pos - 1) > end && (pos[-1] == '/' || pos[-1] == '\\')) {
+          // server name (//server) is a root name
+          if (!check_only) {
+            this->Entry = cm::string_view(pos - 1, ptr - pos + 2);
+          }
+          return pos - 2;
+        }
+      }
+    }
+#  elif defined(__CYGWIN__)
+    if (ptr < end) {
+      if ((end - ptr) > 2 && ptr[0] == '/' && ptr[1] == '/' && ptr[2] != '/') {
+        // server name (//server) is a root name
+        auto pos = std::find(ptr + 2, end, '/');
+        if (!check_only) {
+          this->Entry = cm::string_view(ptr, pos - ptr);
+        }
+        return pos;
+      }
+    } else {
+      if ((ptr - end) > 2 && ptr[0] != '/') {
+        std::reverse_iterator<pointer> start(ptr);
+        std::reverse_iterator<pointer> stop(end);
+        auto res = std::find(start, stop, '/');
+        pointer pos = res.base() - 1;
+        if ((pos - 1) > end && pos[-1] == '/') {
+          // server name (//server) is a root name
+          if (!check_only) {
+            this->Entry = cm::string_view(pos - 1, ptr - pos + 2);
+          }
+          return pos - 2;
+        }
+      }
+    }
+#  else
+    (void)ptr;
+    (void)end;
+    (void)check_only;
+#  endif
+    return nullptr;
+  }
+
+  state State;
+  const cm::string_view Path;
+  cm::string_view Entry;
+};
+
+// class unicode_helper
+void unicode_helper::append(std::string& str, std::uint32_t codepoint)
+{
+  if (codepoint <= 0x7f) {
+    str.push_back(static_cast<char>(codepoint));
+  } else if (codepoint >= 0x80 && codepoint <= 0x7ff) {
+    str.push_back(static_cast<char>((codepoint >> 6) + 192));
+    str.push_back(static_cast<char>((codepoint & 0x3f) + 128));
+  } else if ((codepoint >= 0x800 && codepoint <= 0xd7ff) ||
+             (codepoint >= 0xe000 && codepoint <= 0xffff)) {
+    str.push_back(static_cast<char>((codepoint >> 12) + 224));
+    str.push_back(static_cast<char>(((codepoint & 0xfff) >> 6) + 128));
+    str.push_back(static_cast<char>((codepoint & 0x3f) + 128));
+  } else if (codepoint >= 0x10000 && codepoint <= 0x10ffff) {
+    str.push_back(static_cast<char>((codepoint >> 18) + 240));
+    str.push_back(static_cast<char>(((codepoint & 0x3ffff) >> 12) + 128));
+    str.push_back(static_cast<char>(((codepoint & 0xfff) >> 6) + 128));
+    str.push_back(static_cast<char>((codepoint & 0x3f) + 128));
+  } else {
+    append(str, 0xfffd);
+  }
+}
+
+unicode_helper::utf8_state unicode_helper::decode(const utf8_state state,
+                                                  const std::uint8_t fragment,
+                                                  std::uint32_t& codepoint)
+{
+  const std::uint32_t utf8_state_info[] = {
+    // encoded states
+    0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u,
+    0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u,
+    0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu,
+    0x99999999u, 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u,
+    0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u,
+    0x88888888u, 0x88888883u, 0x88888885u, 0u,          0u,
+    0u,          0u,
+  };
+  std::uint8_t category = fragment < 128
+    ? 0
+    : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf;
+  codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu)
+                     : (0xffu >> category) & fragment);
+  return state == s_reject
+    ? s_reject
+    : static_cast<utf8_state>(
+        (utf8_state_info[category + 16] >> (state << 2)) & 0xf);
+}
+
+} // internals
+
+// Class path
+path& path::operator/=(const path& p)
+{
+  if (p.is_absolute() ||
+      (p.has_root_name() && p.get_root_name() != this->get_root_name())) {
+    this->path_ = p.path_;
+    return *this;
+  }
+  if (p.has_root_directory()) {
+    this->path_ = static_cast<std::string>(this->get_root_name());
+    this->path_ += static_cast<std::string>(p.get_root_directory());
+  } else if (this->has_filename()) {
+    this->path_ += this->preferred_separator;
+#  if defined(_WIN32) || defined(__CYGWIN__)
+    // special case: "//host" / "b" => "//host/b"
+  } else if (this->has_root_name() && !this->has_root_directory()) {
+    if (this->path_.length() >= 3 &&
+        (this->path_[0] == '/'
+#    if defined(_WIN32) && !defined(__CYGWIN__)
+         || this->path_[0] == '\\'
+#    endif
+         ) &&
+        (this->path_[1] == '/'
+#    if defined(_WIN32) && !defined(__CYGWIN__)
+         || this->path_[1] == '\\'
+#    endif
+         ) &&
+        (this->path_[2] != '/'
+#    if defined(_WIN32) && !defined(__CYGWIN__)
+         && this->path_[2] != '\\'
+#    endif
+         )) {
+      this->path_ += this->preferred_separator;
+    }
+#  endif
+  }
+
+  this->path_ += p.get_relative_path();
+  return *this;
+}
+
+path path::lexically_normal() const
+{
+  if (this->path_.empty()) {
+    return *this;
+  }
+
+  const cm::string_view dot = "."_s;
+  const cm::string_view dotdot = ".."_s;
+
+  std::vector<cm::string_view> root_parts;
+  std::vector<cm::string_view> parts;
+  bool root_directory_defined = false;
+  bool need_final_separator = false;
+  std::size_t path_size = 0;
+
+  internals::path_parser parser(this->path_);
+  ++parser;
+  while (!parser.at_end()) {
+    auto part = *parser;
+
+    if (parser.in_root_name() || parser.in_root_directory()) {
+      if (parser.in_root_directory()) {
+        root_directory_defined = true;
+      }
+      root_parts.push_back(part);
+      path_size += part.size();
+    } else if (part == dotdot) {
+      if (!parts.empty() && parts.back() != dotdot) {
+        need_final_separator = true;
+        path_size -= parts.back().size();
+        parts.pop_back();
+      } else if ((parts.empty() || parts.back() == dotdot) &&
+                 !root_directory_defined) {
+        parts.push_back(dotdot);
+        path_size += 2;
+      }
+
+    } else if (part == dot || part.empty()) {
+      need_final_separator = true;
+      if (part.empty()) {
+        parts.push_back(part);
+      }
+    } else {
+      // filename
+      need_final_separator = false;
+      parts.push_back(part);
+      path_size += part.size();
+    }
+    ++parser;
+  }
+
+  // no final separator if last element of path is ".."
+  need_final_separator =
+    need_final_separator && !parts.empty() && parts.back() != dotdot;
+
+  // build final path
+  //// compute final size of path
+  path_size += parts.size() + (need_final_separator ? 1 : 0);
+
+  std::string np;
+  np.reserve(path_size);
+  for (const auto& p : root_parts) {
+    np += p;
+  }
+  // convert any slash to the preferred_separator
+  if (static_cast<std::string::value_type>(this->preferred_separator) != '/') {
+    std::replace(
+      np.begin(), np.end(), '/',
+      static_cast<std::string::value_type>(this->preferred_separator));
+  }
+  for (const auto& p : parts) {
+    if (!p.empty()) {
+      np += p;
+      np += static_cast<std::string::value_type>(this->preferred_separator);
+    }
+  }
+  if (!parts.empty() && !need_final_separator) {
+    // remove extra separator
+    np.pop_back();
+  }
+  if (np.empty()) {
+    np.assign(1, '.');
+  }
+
+  return path(std::move(np));
+}
+
+path path::lexically_relative(const path& base) const
+{
+  internals::path_parser parser(this->path_);
+  ++parser;
+  internals::path_parser parserbase(base.path_);
+  ++parserbase;
+  cm::string_view this_root_name, base_root_name;
+  cm::string_view this_root_dir, base_root_dir;
+
+  if (parser.in_root_name()) {
+    this_root_name = *parser;
+    ++parser;
+  }
+  if (parser.in_root_directory()) {
+    this_root_dir = *parser;
+    ++parser;
+  }
+  if (parserbase.in_root_name()) {
+    base_root_name = *parserbase;
+    ++parserbase;
+  }
+  if (parserbase.in_root_directory()) {
+    base_root_dir = *parserbase;
+    ++parserbase;
+  }
+
+  auto is_path_absolute = [](cm::string_view rn, cm::string_view rd) -> bool {
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+    return !rn.empty() && !rd.empty();
+#  else
+    (void)rn;
+    return !rd.empty();
+#  endif
+  };
+
+  if (this_root_name != base_root_name ||
+      is_path_absolute(this_root_name, this_root_dir) !=
+        is_path_absolute(base_root_name, base_root_dir) ||
+      (this_root_dir.empty() && !base_root_dir.empty())) {
+    return path();
+  }
+
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+  // LWG3070 handle special case: filename can also be a root-name
+  auto is_drive_name = [](cm::string_view item) -> bool {
+    return item.length() == 2 && item[1] == ':';
+  };
+  parser.reset();
+  parser.seek(internals::path_parser::seek_position::root_directory);
+  while (!parser.at_end()) {
+    if (is_drive_name(*parser)) {
+      return path();
+    }
+    ++parser;
+  }
+  parserbase.reset();
+  parserbase.seek(internals::path_parser::seek_position::root_directory);
+  while (!parserbase.at_end()) {
+    if (is_drive_name(*parserbase)) {
+      return path();
+    }
+    ++parserbase;
+  }
+#  endif
+
+  const cm::string_view dot = "."_s;
+  const cm::string_view dotdot = ".."_s;
+
+  auto a = this->begin(), aend = this->end();
+  auto b = base.begin(), bend = base.end();
+  while (a != aend && b != bend && a->string() == b->string()) {
+    ++a;
+    ++b;
+  }
+
+  int count = 0;
+  for (; b != bend; ++b) {
+    auto part = *b;
+    if (part == dotdot) {
+      --count;
+    } else if (part.string() != dot && !part.empty()) {
+      ++count;
+    }
+  }
+
+  if (count == 0 && (a == this->end() || a->empty())) {
+    return path(dot);
+  }
+  if (count >= 0) {
+    path result;
+    path p_dotdot(dotdot);
+    for (int i = 0; i < count; ++i) {
+      result /= p_dotdot;
+    }
+    for (; a != aend; ++a) {
+      result /= *a;
+    }
+    return result;
+  }
+  // count < 0
+  return path();
+}
+
+path::path_type path::get_generic() const
+{
+  auto gen_path = this->path_;
+  auto start = gen_path.begin();
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+  std::replace(gen_path.begin(), gen_path.end(), '\\', '/');
+  // preserve special syntax for root_name ('//server' or '//?')
+  if (gen_path.length() > 2 && gen_path[2] != '/') {
+    start += 2;
+  }
+#  endif
+  // remove duplicate separators
+  auto new_end = std::unique(start, gen_path.end(), [](char lhs, char rhs) {
+    return lhs == rhs && lhs == '/';
+  });
+  gen_path.erase(new_end, gen_path.end());
+  return gen_path;
+}
+
+cm::string_view path::get_root_name() const
+{
+  internals::path_parser parser(this->path_);
+  ++parser;
+  if (parser.in_root_name()) {
+    return *parser;
+  }
+  return {};
+}
+
+cm::string_view path::get_root_directory() const
+{
+  internals::path_parser parser(this->path_);
+  ++parser;
+  if (parser.in_root_name()) {
+    ++parser;
+  }
+  if (parser.in_root_directory()) {
+    return *parser;
+  }
+  return {};
+}
+
+cm::string_view path::get_relative_path() const
+{
+  internals::path_parser parser(this->path_);
+  parser.seek(internals::path_parser::seek_position::root_directory);
+  if (parser.at_end()) {
+    return {};
+  }
+  return parser.peek(internals::path_parser::peek_fragment::remainder);
+}
+
+cm::string_view path::get_parent_path() const
+{
+  if (!this->has_relative_path()) {
+    return this->path_;
+  }
+
+  // peek-up full path minus last element
+  internals::path_parser parser(this->path_, true);
+  --parser;
+  if (parser.at_start()) {
+    return {};
+  }
+  --parser;
+  return parser.peek(internals::path_parser::peek_fragment::path);
+}
+
+cm::string_view path::get_filename() const
+{
+  {
+    internals::path_parser parser(this->path_);
+    parser.seek(internals::path_parser::seek_position::root_directory);
+    if (parser.at_end()) {
+      return {};
+    }
+  }
+  {
+    internals::path_parser parser(this->path_, true);
+    return *(--parser);
+  }
+}
+
+cm::string_view path::get_filename_fragment(filename_fragment fragment) const
+{
+  auto file = this->get_filename();
+
+  if (file == "." || file == ".." || file.empty()) {
+    return fragment == filename_fragment::stem ? file : cm::string_view{};
+  }
+
+  auto pos = file.find_last_of('.');
+  if (pos == cm::string_view::npos || pos == 0) {
+    return fragment == filename_fragment::stem ? file : cm::string_view{};
+  }
+  return fragment == filename_fragment::stem ? file.substr(0, pos)
+                                             : file.substr(pos);
+}
+
+int path::compare_path(cm::string_view str) const
+{
+  internals::path_parser this_pp(this->path_);
+  ++this_pp;
+  internals::path_parser other_pp(str);
+  ++other_pp;
+
+  // compare root_name part
+  {
+    bool compare_root_names = false;
+    cm::string_view this_root_name, other_root_name;
+    int res;
+
+    if (this_pp.in_root_name()) {
+      compare_root_names = true;
+      this_root_name = *this_pp;
+      ++this_pp;
+    }
+    if (other_pp.in_root_name()) {
+      compare_root_names = true;
+      other_root_name = *other_pp;
+      ++other_pp;
+    }
+    if (compare_root_names &&
+        (res = this_root_name.compare(other_root_name) != 0)) {
+      return res;
+    }
+  }
+
+  // compare root_directory part
+  {
+    if (!this_pp.in_root_directory() && other_pp.in_root_directory()) {
+      return -1;
+    } else if (this_pp.in_root_directory() && !other_pp.in_root_directory()) {
+      return 1;
+    }
+    if (this_pp.in_root_directory()) {
+      ++this_pp;
+    }
+    if (other_pp.in_root_directory()) {
+      ++other_pp;
+    }
+  }
+
+  // compare various parts of the paths
+  while (!this_pp.at_end() && !other_pp.at_end()) {
+    int res;
+    if ((res = (*this_pp).compare(*other_pp)) != 0) {
+      return res;
+    }
+    ++this_pp;
+    ++other_pp;
+  }
+
+  // final step
+  if (this_pp.at_end() && !other_pp.at_end()) {
+    return -1;
+  } else if (!this_pp.at_end() && other_pp.at_end()) {
+    return 1;
+  }
+
+  return 0;
+}
+
+// Class path::iterator
+path::iterator::iterator()
+  : path_(nullptr)
+{
+}
+path::iterator::iterator(const iterator& other)
+{
+  this->path_ = other.path_;
+  if (other.parser_) {
+    this->parser_ = cm::make_unique<internals::path_parser>(*other.parser_);
+    this->path_element_ = path(**this->parser_);
+  }
+}
+path::iterator::iterator(const path* p, bool at_end)
+  : path_(p)
+  , parser_(cm::make_unique<internals::path_parser>(p->path_, at_end))
+{
+  if (!at_end) {
+    ++(*this->parser_);
+    this->path_element_ = path(**this->parser_);
+  }
+}
+
+path::iterator::~iterator() = default;
+
+path::iterator& path::iterator::operator=(const iterator& other)
+{
+  this->path_ = other.path_;
+  if (other.parser_) {
+    this->parser_ = cm::make_unique<internals::path_parser>(*other.parser_);
+    this->path_element_ = path(**this->parser_);
+  }
+
+  return *this;
+}
+
+path::iterator& path::iterator::operator++()
+{
+  assert(this->parser_);
+
+  if (this->parser_) {
+    assert(!this->parser_->at_end());
+
+    if (!this->parser_->at_end()) {
+      ++(*this->parser_);
+      if (this->parser_->at_end()) {
+        this->path_element_ = path();
+      } else {
+        this->path_element_ = path(**this->parser_);
+      }
+    }
+  }
+
+  return *this;
+}
+
+path::iterator& path::iterator::operator--()
+{
+  assert(this->parser_);
+
+  if (this->parser_) {
+    assert(!this->parser_->at_start());
+
+    if (!this->parser_->at_start()) {
+      --(*this->parser_);
+      this->path_element_ = path(**this->parser_);
+    }
+  }
+
+  return *this;
+}
+
+bool operator==(const path::iterator& lhs, const path::iterator& rhs)
+{
+  return lhs.path_ == rhs.path_ && lhs.parser_ != nullptr &&
+    ((lhs.parser_->at_end() && rhs.parser_->at_end()) ||
+     (lhs.parser_->at_start() && rhs.parser_->at_start()) ||
+     ((**lhs.parser_).data() == (**rhs.parser_).data()));
+}
+
+std::size_t hash_value(const path& p) noexcept
+{
+  internals::path_parser parser(p.path_);
+  std::hash<cm::string_view> hasher;
+  std::size_t value = 0;
+
+  while (!parser.at_end()) {
+    value = hasher(*parser) + 0x9e3779b9 + (value << 6) + (value >> 2);
+    ++parser;
+  }
+
+  return value;
+}
+} // filesystem
+} // cm
+
+#else
+
+// Avoid empty translation unit.
+void cm_filesystem_path_cxx()
+{
+}
+
+#endif
diff --git a/Utilities/std/cm/filesystem b/Utilities/std/cm/filesystem
new file mode 100644
index 0000000..6021712
--- /dev/null
+++ b/Utilities/std/cm/filesystem
@@ -0,0 +1,1175 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_filesystem
+#define cm_filesystem
+
+#include "cmSTL.hxx" // IWYU pragma: keep
+
+#if defined(CMake_HAVE_CXX_FILESYSTEM)
+
+#  include <filesystem> // IWYU pragma: export
+
+#else
+
+#  include <cstddef>
+#  include <cstdint>
+#  include <iostream>
+#  include <iterator>
+#  include <memory>
+#  include <string>
+#  include <utility>
+
+#  include <cm/iomanip>
+#  include <cm/string_view>
+#  include <cm/type_traits>
+#  include <cmext/iterator>
+
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+#    include <algorithm>
+#  endif
+
+#endif
+
+namespace cm {
+namespace filesystem {
+
+#if defined(CMake_HAVE_CXX_FILESYSTEM)
+
+using std::filesystem::path;
+using std::filesystem::swap;
+using std::filesystem::hash_value;
+
+#else
+
+#  if !defined(CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR)
+// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
+// the source_traits for iterator check.  So disable it for now.
+#    define CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR 0
+#  endif
+
+namespace internals {
+
+class path_parser;
+
+class unicode_helper
+{
+protected:
+  using utf8_state = unsigned char;
+  static const utf8_state s_start = 0;
+  static const utf8_state s_reject = 8;
+
+  static inline bool in_range(std::uint32_t c, std::uint32_t lo,
+                              std::uint32_t hi)
+  {
+    return (static_cast<std::uint32_t>(c - lo) < (hi - lo + 1));
+  }
+
+  static inline bool is_surrogate(std::uint32_t c)
+  {
+    return in_range(c, 0xd800, 0xdfff);
+  }
+
+  static inline bool is_high_surrogate(std::uint32_t c)
+  {
+    return (c & 0xfffffc00) == 0xd800;
+  }
+
+  static inline bool is_low_surrogate(std::uint32_t c)
+  {
+    return (c & 0xfffffc00) == 0xdc00;
+  }
+
+  static void append(std::string& str, std::uint32_t codepoint);
+
+  static utf8_state decode(const utf8_state state, const std::uint8_t fragment,
+                           std::uint32_t& codepoint);
+};
+
+template <typename Char, typename = void>
+class unicode
+{
+};
+
+template <typename Char>
+class unicode<Char, typename std::enable_if<(sizeof(Char) == 4)>::type>
+  : public unicode_helper
+{
+public:
+  // UTF32 -> UTF8
+  static std::string to_utf8(const std::wstring& str)
+  {
+    std::string result;
+    for (auto c : str) {
+      append(result, c);
+    }
+    return result;
+  }
+  static std::string to_utf8(Char c)
+  {
+    std::string result;
+    append(result, c);
+    return result;
+  }
+
+  // UTF8 -> UTF32
+  static std::wstring from_utf8(const std::string& str)
+  {
+    std::wstring result;
+    result.reserve(str.length());
+    auto iter = str.begin();
+    utf8_state state = s_start;
+    std::uint32_t codepoint = 0;
+    while (iter < str.end()) {
+      if ((state = decode(state, static_cast<std::uint8_t>(*iter++),
+                          codepoint)) == s_start) {
+        result += static_cast<std::wstring::value_type>(codepoint);
+        codepoint = 0;
+      } else if (state == s_reject) {
+        result += static_cast<std::wstring::value_type>(0xfffd);
+        state = s_start;
+        codepoint = 0;
+      }
+    }
+    if (state) {
+      result += static_cast<std::wstring::value_type>(0xfffd);
+    }
+    return result;
+  }
+  static std::wstring from_utf8(char c)
+  {
+    std::wstring result;
+    utf8_state state = s_start;
+    std::uint32_t codepoint = 0;
+    if ((state = decode(state, static_cast<std::uint8_t>(c), codepoint)) ==
+        s_start) {
+      result += static_cast<std::wstring::value_type>(codepoint);
+    } else {
+      result += static_cast<std::wstring::value_type>(0xfffd);
+    }
+
+    return result;
+  }
+};
+
+template <typename Char>
+class unicode<Char, typename std::enable_if<(sizeof(Char) == 2)>::type>
+  : public unicode_helper
+{
+public:
+  // UTF16 -> UTF8
+  static std::string to_utf8(const std::wstring& str)
+  {
+    std::string result;
+    for (auto iter = str.begin(); iter != str.end(); ++iter) {
+      std::uint32_t c = *iter;
+      if (is_surrogate(c)) {
+        ++iter;
+        if (iter != str.end() && is_high_surrogate(c) &&
+            is_low_surrogate(*iter)) {
+          append(result, (std::uint32_t(c) << 10) + *iter - 0x35fdc00);
+        } else {
+          append(result, 0xfffd);
+          if (iter == str.end()) {
+            break;
+          }
+        }
+      } else {
+        append(result, c);
+      }
+    }
+    return result;
+  }
+  static std::string to_utf8(Char c)
+  {
+    std::string result;
+    if (is_surrogate(c)) {
+      append(result, 0xfffd);
+    } else {
+      append(result, c);
+    }
+    return result;
+  }
+
+  // UTF8 -> UTF16
+  static std::wstring from_utf8(const std::string& str)
+  {
+    std::wstring result;
+    result.reserve(str.length());
+    auto iter = str.begin();
+    utf8_state state = s_start;
+    std::uint32_t codepoint = 0;
+    while (iter < str.end()) {
+      if ((state = decode(state, static_cast<std::uint8_t>(*iter++),
+                          codepoint)) == s_start) {
+        if (codepoint <= 0xffff) {
+          result += static_cast<std::wstring::value_type>(codepoint);
+        } else {
+          codepoint -= 0x10000;
+          result +=
+            static_cast<std::wstring::value_type>((codepoint >> 10) + 0xd800);
+          result += static_cast<std::wstring::value_type>((codepoint & 0x3ff) +
+                                                          0xdc00);
+        }
+        codepoint = 0;
+      } else if (state == s_reject) {
+        result += static_cast<std::wstring::value_type>(0xfffd);
+        state = s_start;
+        codepoint = 0;
+      }
+    }
+    if (state) {
+      result += static_cast<std::wstring::value_type>(0xfffd);
+    }
+    return result;
+  }
+  static std::wstring from_utf8(char c)
+  {
+    std::wstring result;
+    utf8_state state = s_start;
+    std::uint32_t codepoint = 0;
+    if ((state = decode(state, static_cast<std::uint8_t>(c), codepoint)) ==
+        s_start) {
+      if (codepoint <= 0xffff) {
+        result += static_cast<std::wstring::value_type>(codepoint);
+      } else {
+        codepoint -= 0x10000;
+        result +=
+          static_cast<std::wstring::value_type>((codepoint >> 10) + 0xd800);
+        result +=
+          static_cast<std::wstring::value_type>((codepoint & 0x3ff) + 0xdc00);
+      }
+    } else {
+      result += static_cast<std::wstring::value_type>(0xfffd);
+    }
+    return result;
+  }
+};
+
+template <typename In, typename Out>
+class unicode_converter;
+
+template <>
+class unicode_converter<char, wchar_t>
+{
+public:
+  std::wstring operator()(const std::string& in)
+  {
+    return unicode<wchar_t>::from_utf8(in);
+  }
+  std::wstring operator()(const char* in)
+  {
+    return unicode<wchar_t>::from_utf8(in);
+  }
+  std::wstring operator()(char in) { return unicode<wchar_t>::from_utf8(in); }
+};
+template <>
+class unicode_converter<wchar_t, char>
+{
+public:
+  std::string operator()(const std::wstring& in)
+  {
+    return unicode<wchar_t>::to_utf8(in);
+  }
+  std::string operator()(const wchar_t* in)
+  {
+    return unicode<wchar_t>::to_utf8(in);
+  }
+  std::string operator()(wchar_t in) { return unicode<wchar_t>::to_utf8(in); }
+};
+template <>
+class unicode_converter<char, char>
+{
+public:
+  std::string operator()(const std::string& in) { return in; }
+  std::string operator()(const char* in) { return std::string(in); }
+  std::string operator()(char in) { return std::string(1, in); }
+};
+template <>
+class unicode_converter<wchar_t, wchar_t>
+{
+public:
+  std::wstring operator()(const std::wstring& in) { return in; }
+  std::wstring operator()(const wchar_t* in) { return std::wstring(in); }
+  std::wstring operator()(wchar_t in) { return std::wstring(1, in); }
+};
+
+template <typename In>
+struct string_converter
+{
+};
+
+template <>
+struct string_converter<char>
+{
+  // some compilers, like gcc 4.8 does not implement the following C++11
+  // signature:
+  // std::string::string(const string&, const Allocator&)
+  // As workaround, use char* pointer.
+  template <typename Char, typename Traits, typename Alloc>
+  static std::basic_string<Char, Traits, Alloc> to(const std::string& in,
+                                                   const Alloc& a)
+  {
+    return std::basic_string<Char, Traits, Alloc>(
+      unicode_converter<char, Char>()(in).c_str(), a);
+  }
+  template <typename Char, typename Traits, typename Alloc>
+  static std::basic_string<Char, Traits, Alloc> to(const char* in,
+                                                   const Alloc& a)
+  {
+    return std::basic_string<Char, Traits, Alloc>(
+      unicode_converter<char, Char>()(in).c_str(), a);
+  }
+  template <typename Char, typename Traits, typename Alloc>
+  static std::basic_string<Char, Traits, Alloc> to(char in, const Alloc& a)
+  {
+    return std::basic_string<Char, Traits, Alloc>(
+      unicode_converter<char, Char>()(in).c_str(), a);
+  }
+
+  template <typename Char>
+  static std::basic_string<Char> to(const std::string& in)
+  {
+    return std::basic_string<Char>(unicode_converter<char, Char>()(in));
+  }
+  template <typename Char>
+  static std::basic_string<Char> to(const char* in)
+  {
+    return std::basic_string<Char>(unicode_converter<char, Char>()(in));
+  }
+  template <typename Char>
+  static std::basic_string<Char> to(char in)
+  {
+    return std::basic_string<Char>(unicode_converter<char, Char>()(in));
+  }
+};
+template <>
+struct string_converter<wchar_t>
+{
+  // some compilers, like gcc 4.8 does not implement the following C++11
+  // signature:
+  // std::string::string(const string&, const Allocator&)
+  // As workaround, use char* pointer.
+  template <typename Char, typename Traits, typename Alloc>
+  static std::basic_string<Char, Traits, Alloc> to(const std::wstring& in,
+                                                   const Alloc& a)
+  {
+    return std::basic_string<Char, Traits, Alloc>(
+      unicode_converter<wchar_t, Char>()(in).c_str(), a);
+  }
+  template <typename Char, typename Traits, typename Alloc>
+  static std::basic_string<Char, Traits, Alloc> to(const wchar_t* in,
+                                                   const Alloc& a)
+  {
+    return std::basic_string<Char, Traits, Alloc>(
+      unicode_converter<wchar_t, Char>()(in).c_str(), a);
+  }
+  template <typename Char, typename Traits, typename Alloc>
+  static std::basic_string<Char, Traits, Alloc> to(wchar_t in, const Alloc& a)
+  {
+    return std::basic_string<Char, Traits, Alloc>(
+      unicode_converter<wchar_t, Char>()(in).c_str(), a);
+  }
+
+  template <typename Char>
+  static std::basic_string<Char> to(const std::wstring& in)
+  {
+    return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
+  }
+  template <typename Char>
+  static std::basic_string<Char> to(const wchar_t* in)
+  {
+    return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
+  }
+  template <typename Char>
+  static std::basic_string<Char> to(wchar_t in)
+  {
+    return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
+  }
+};
+
+template <typename T, typename = void>
+struct source_traits
+{
+};
+
+template <typename T, std::size_t N>
+struct source_traits<T[N]>
+{
+  using value_type = T;
+};
+
+template <typename Char, typename Traits, typename Alloc>
+struct source_traits<std::basic_string<Char, Traits, Alloc>>
+{
+  using value_type =
+    typename std::basic_string<Char, Traits, Alloc>::value_type;
+};
+
+template <>
+struct source_traits<cm::string_view>
+{
+  using value_type = cm::string_view::value_type;
+};
+
+#  if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
+template <typename T>
+struct source_traits<T, cm::enable_if_t<cm::is_iterator<T>::value, void>>
+{
+  using value_type =
+    typename std::iterator_traits<typename std::decay<T>::type>::value_type;
+};
+#  endif
+
+template <typename In, typename Out>
+struct source_converter
+{
+};
+
+template <>
+struct source_converter<char, char>
+{
+  template <typename Iterator>
+  static void append_range(std::string& p, Iterator b, Iterator e)
+  {
+    if (b == e) {
+      return;
+    }
+    p.append(b, e);
+  }
+  template <typename Iterator>
+  static void append_range(std::string& p, Iterator b)
+  {
+    char e = '\0';
+
+    if (*b == e) {
+      return;
+    }
+    for (; *b != e; ++b) {
+      p.push_back(*b);
+    }
+  }
+
+  static void append_source(std::string& p, const cm::string_view s)
+  {
+    append_range(p, s.begin(), s.end());
+  }
+  template <typename Traits, typename Alloc>
+  static void append_source(std::string& p,
+                            const std::basic_string<char, Traits, Alloc>& s)
+  {
+    append_range(p, s.begin(), s.end());
+  }
+  template <typename Source>
+  static void append_source(std::string& p, const Source& s)
+  {
+    append_range(p, s);
+  }
+
+  static void set_source(std::string& p, std::string&& s) { p = std::move(s); }
+};
+
+template <>
+struct source_converter<wchar_t, char>
+{
+  template <typename Iterator>
+  static void append_range(std::string& p, Iterator b, Iterator e)
+  {
+    if (b == e) {
+      return;
+    }
+
+    std::wstring tmp(b, e);
+    std::string dest = string_converter<wchar_t>::to<char>(tmp);
+    p.append(dest.begin(), dest.end());
+  }
+  template <typename Iterator>
+  static void append_range(std::string& p, Iterator b)
+  {
+    wchar_t e = '\0';
+
+    if (*b == e) {
+      return;
+    }
+    std::wstring tmp;
+    for (; *b != e; ++b) {
+      tmp.push_back(*b);
+    }
+
+    std::string dest = string_converter<wchar_t>::to<char>(tmp);
+    p.append(dest.begin(), dest.end());
+  }
+
+  template <typename Traits, typename Alloc>
+  static void append_source(std::string& p,
+                            const std::basic_string<wchar_t, Traits, Alloc>& s)
+  {
+    append_range(p, s.begin(), s.end());
+  }
+  template <typename Source>
+  static void append_source(std::string& p, const Source& s)
+  {
+    append_range(p, s);
+  }
+
+  static void set_source(std::string& p, std::wstring&& s)
+  {
+    p = string_converter<wchar_t>::to<char>(s);
+  }
+};
+
+template <typename T>
+struct is_pathable_string : std::false_type
+{
+};
+template <typename Traits, typename Alloc>
+struct is_pathable_string<std::basic_string<char, Traits, Alloc>>
+  : std::true_type
+{
+};
+template <typename Traits, typename Alloc>
+struct is_pathable_string<std::basic_string<wchar_t, Traits, Alloc>>
+  : std::true_type
+{
+};
+template <>
+struct is_pathable_string<cm::string_view> : std::true_type
+{
+};
+
+template <typename T, typename = void>
+struct is_pathable_char_array : std::false_type
+{
+};
+template <typename T>
+struct is_pathable_char_array<
+  T,
+  cm::enable_if_t<
+    std::is_same<char*, typename std::decay<T>::type>::value ||
+      std::is_same<wchar_t*, typename std::decay<T>::type>::value,
+    void>>
+  : bool_constant<std::is_same<char*, typename std::decay<T>::type>::value ||
+                  std::is_same<wchar_t*, typename std::decay<T>::type>::value>
+{
+};
+
+template <typename T, typename = void>
+struct is_pathable_iterator : std::false_type
+{
+};
+template <typename T>
+struct is_pathable_iterator<
+  T,
+  cm::enable_if_t<
+    is_input_iterator<T>::value &&
+      (std::is_same<char,
+                    typename std::iterator_traits<
+                      typename std::decay<T>::type>::value_type>::value ||
+       std::is_same<wchar_t,
+                    typename std::iterator_traits<
+                      typename std::decay<T>::type>::value_type>::value),
+    void>>
+  : bool_constant<
+      std::is_same<char,
+                   typename std::iterator_traits<
+                     typename std::decay<T>::type>::value_type>::value ||
+      std::is_same<wchar_t,
+                   typename std::iterator_traits<
+                     typename std::decay<T>::type>::value_type>::value>
+{
+};
+
+#  if defined(__SUNPRO_CC) && defined(__sparc)
+// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
+// the full 'is_pathable' check.  We use it only to improve error messages
+// via 'enable_if' when calling methods with incorrect types.  Just
+// pretend all types are allowed so we can at least compile valid code.
+template <typename T>
+struct is_pathable : std::true_type
+{
+};
+#  else
+template <typename T>
+struct is_pathable
+  : bool_constant<is_pathable_string<T>::value ||
+                  is_pathable_char_array<T>::value ||
+                  is_pathable_iterator<T>::value>
+{
+};
+#  endif
+}
+
+class path
+{
+  using path_type = std::string;
+
+  template <typename Source>
+  using enable_if_pathable =
+    enable_if_t<internals::is_pathable<Source>::value, path&>;
+
+  enum class filename_fragment : unsigned char
+  {
+    stem,
+    extension
+  };
+
+public:
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+  using value_type = wchar_t;
+#  else
+  using value_type = char;
+#  endif
+  using string_type = std::basic_string<value_type>;
+
+  class iterator;
+  using const_iterator = iterator;
+
+  enum format : unsigned char
+  {
+    auto_format,
+    native_format,
+    generic_format
+  };
+
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+  static constexpr value_type preferred_separator = L'\\';
+#  else
+  static constexpr value_type preferred_separator = '/';
+#  endif
+
+  // Constructors
+  // ============
+  path() noexcept {}
+  path(const path& p)
+    : path_(p.path_)
+  {
+  }
+  path(path&& p) noexcept
+    : path_(std::move(p.path_))
+  {
+  }
+  path(string_type&& source, format fmt = auto_format)
+  {
+    (void)fmt;
+    internals::source_converter<value_type, path_type::value_type>::set_source(
+      this->path_, std::move(source));
+  }
+  template <typename Source, typename = enable_if_pathable<Source>>
+  path(const Source& source, format fmt = auto_format)
+  {
+    (void)fmt;
+    internals::source_converter<
+      typename internals::source_traits<Source>::value_type,
+      path_type::value_type>::append_source(this->path_, source);
+  }
+  template <typename Iterator, typename = enable_if_pathable<Iterator>>
+  path(const Iterator first, Iterator last, format fmt = auto_format)
+  {
+    (void)fmt;
+    internals::source_converter<
+      typename std::iterator_traits<Iterator>::value_type,
+      path_type::value_type>::append_range(this->path_, first, last);
+  }
+
+  ~path() = default;
+
+  // Assignments
+  // ===========
+  path& operator=(const path& p)
+  {
+    if (this != &p) {
+      this->path_ = p.path_;
+    }
+    return *this;
+  }
+  path& operator=(path&& p) noexcept
+  {
+    if (this != &p) {
+      this->path_ = std::move(p.path_);
+    }
+    return *this;
+  }
+  path& operator=(string_type&& source) { return this->assign(source); }
+  template <typename Source, typename = enable_if_pathable<Source>>
+  path& operator=(const Source& source)
+  {
+    return this->assign(source);
+  }
+
+  path& assign(string_type&& source)
+  {
+    internals::source_converter<value_type, path_type::value_type>::set_source(
+      this->path_, std::move(source));
+    return *this;
+  }
+  template <typename Source, typename = enable_if_pathable<Source>>
+  path& assign(const Source& source)
+  {
+    this->path_.clear();
+    internals::source_converter<
+      typename internals::source_traits<Source>::value_type,
+      path_type::value_type>::append_source(this->path_, source);
+    return *this;
+  }
+  template <typename Iterator, typename = enable_if_pathable<Iterator>>
+  path& assign(Iterator first, Iterator last)
+  {
+    this->path_.clear();
+    internals::source_converter<
+      typename std::iterator_traits<Iterator>::value_type,
+      path_type::value_type>::append_range(this->path_, first, last);
+    return *this;
+  }
+
+  // Concatenation
+  // =============
+  path& operator/=(const path& p);
+
+  template <typename Source, typename = enable_if_pathable<Source>>
+  path& append(const Source& source)
+  {
+    return this->operator/=(path(source));
+  }
+  template <typename Source>
+  path& operator/=(const Source& source)
+  {
+    return this->append(source);
+  }
+
+  template <typename Iterator, typename = enable_if_pathable<Iterator>>
+  path& append(Iterator first, Iterator last)
+  {
+    return this->operator/=(path(first, last));
+  }
+
+  path& operator+=(const path& p)
+  {
+    this->path_ += p.path_;
+    return *this;
+  }
+  path& operator+=(const string_type& str)
+  {
+    this->path_ +=
+      internals::string_converter<value_type>::to<path_type::value_type>(str);
+    return *this;
+  }
+  path& operator+=(cm::string_view str)
+  {
+    this->path_.append(str.begin(), str.end());
+    return *this;
+  }
+  path& operator+=(const value_type* str)
+  {
+    this->path_ +=
+      internals::string_converter<value_type>::to<path_type::value_type>(str);
+    return *this;
+  }
+  path& operator+=(const value_type c)
+  {
+    this->path_ +=
+      internals::string_converter<value_type>::to<path_type::value_type>(c);
+    return *this;
+  }
+  template <typename Source, typename = enable_if_pathable<Source>>
+  path& concat(const Source& source)
+  {
+    internals::source_converter<
+      typename internals::source_traits<Source>::value_type,
+      path_type::value_type>::append_source(this->path_, source);
+    return *this;
+  }
+  template <typename Source>
+  path& operator+=(const Source& source)
+  {
+    return this->concat(source);
+  }
+  template <typename Iterator, typename = enable_if_pathable<Iterator>>
+  path& concat(Iterator first, Iterator last)
+  {
+    internals::source_converter<
+      typename std::iterator_traits<Iterator>::value_type,
+      path_type::value_type>::append_range(this->path_, first, last);
+    return *this;
+  }
+
+  // Modifiers
+  // =========
+  void clear() noexcept { this->path_.clear(); }
+
+  path& make_preferred()
+  {
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+    std::replace(
+      this->path_.begin(), this->path_.end(), '/',
+      static_cast<path_type::value_type>(this->preferred_separator));
+#  endif
+    return *this;
+  }
+
+  path& remove_filename()
+  {
+    auto fname = this->get_filename();
+    if (!fname.empty()) {
+      this->path_.erase(fname.data() - this->path_.data());
+    }
+    return *this;
+  }
+
+  path& replace_filename(const path& replacement)
+  {
+    this->remove_filename();
+    this->operator/=(replacement);
+    return *this;
+  }
+
+  path& replace_extension(const path& replacement = path())
+  {
+    auto ext = this->get_filename_fragment(filename_fragment::extension);
+    if (!ext.empty()) {
+      this->path_.erase(ext.data() - this->path_.data());
+    }
+    if (!replacement.path_.empty()) {
+      if (replacement.path_[0] != '.') {
+        this->path_ += '.';
+      }
+      this->path_.append(replacement.path_);
+    }
+    return *this;
+  }
+
+  void swap(path& other) noexcept { this->path_.swap(other.path_); }
+
+  // Format observers
+  // ================
+  const string_type& native() const noexcept
+  {
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+    this->native_path_ = internals::string_converter<
+      path_type::value_type>::to<string_type::value_type>(this->path_);
+    return this->native_path_;
+#  else
+    return this->path_;
+#  endif
+  }
+  const value_type* c_str() const noexcept { return this->native().c_str(); }
+  operator string_type() const { return this->native(); }
+
+  template <
+    typename Char, typename Traits = std::char_traits<Char>,
+    typename Alloc = std::allocator<Char>,
+    cm::enable_if_t<(std::is_same<Char, char>::value &&
+                     std::is_same<Traits, std::char_traits<char>>::value) ||
+                      (std::is_same<Char, wchar_t>::value &&
+                       std::is_same<Traits, std::char_traits<wchar_t>>::value),
+                    int> = 1>
+  std::basic_string<Char, Traits, Alloc> string(const Alloc& a = Alloc()) const
+  {
+    return internals::string_converter<path_type::value_type>::to<Char, Traits,
+                                                                  Alloc>(
+      this->path_, a);
+  }
+  const std::string string() const { return this->path_; }
+  std::wstring wstring() const
+  {
+    std::string out = this->string();
+    return internals::string_converter<path_type::value_type>::to<
+      std::wstring::value_type>(out);
+  }
+
+  template <
+    typename Char, typename Traits = std::char_traits<Char>,
+    typename Alloc = std::allocator<Char>,
+    cm::enable_if_t<(std::is_same<Char, char>::value &&
+                     std::is_same<Traits, std::char_traits<char>>::value) ||
+                      (std::is_same<Char, wchar_t>::value &&
+                       std::is_same<Traits, std::char_traits<wchar_t>>::value),
+                    int> = 1>
+  std::basic_string<Char, Traits, Alloc> generic_string(
+    const Alloc& a = Alloc()) const
+  {
+    return internals::string_converter<path_type::value_type>::to<Char, Traits,
+                                                                  Alloc>(
+      this->get_generic(), a);
+  }
+  std::string generic_string() const { return this->get_generic(); }
+  std::wstring generic_wstring() const
+  {
+    auto dest = this->generic_string();
+    return internals::string_converter<path_type::value_type>::to<
+      std::wstring::value_type>(dest);
+  }
+
+  // Compare
+  // =======
+  int compare(const path& p) const noexcept
+  {
+    return this->compare_path(p.path_);
+  }
+  int compare(const string_type& str) const
+  {
+    return this->compare_path(
+      internals::string_converter<value_type>::to<path_type::value_type>(str));
+  }
+  int compare(const value_type* str) const
+  {
+    return this->compare_path(
+      internals::string_converter<value_type>::to<path_type::value_type>(str));
+  }
+  int compare(cm::string_view str) const { return this->compare_path(str); }
+
+  // Generation
+  // ==========
+  path lexically_normal() const;
+
+  path lexically_relative(const path& base) const;
+
+  path lexically_proximate(const path& base) const
+  {
+    path result = this->lexically_relative(base);
+    return result.empty() ? *this : result;
+  }
+
+  // Decomposition
+  // =============
+  path root_name() const { return get_root_name(); }
+
+  path root_directory() const { return this->get_root_directory(); }
+
+  path root_path() const
+  {
+    return this->root_name().append(this->get_root_directory());
+  }
+
+  path relative_path() const { return this->get_relative_path(); }
+
+  path parent_path() const { return this->get_parent_path(); }
+
+  path filename() const { return this->get_filename(); }
+
+  path stem() const
+  {
+    return this->get_filename_fragment(filename_fragment::stem);
+  }
+  path extension() const
+  {
+    return this->get_filename_fragment(filename_fragment::extension);
+  }
+
+  // Queries
+  // =======
+  bool empty() const noexcept { return this->path_.empty(); }
+
+  bool has_root_name() const { return !this->get_root_name().empty(); }
+
+  bool has_root_directory() const
+  {
+    return !this->get_root_directory().empty();
+  }
+
+  bool has_root_path() const
+  {
+    return this->has_root_name() || this->has_root_directory();
+  }
+
+  bool has_relative_path() const { return !this->get_relative_path().empty(); }
+
+  bool has_parent_path() const { return !this->get_parent_path().empty(); }
+
+  bool has_filename() const { return !this->get_filename().empty(); }
+
+  bool has_stem() const
+  {
+    return !this->get_filename_fragment(filename_fragment::stem).empty();
+  }
+  bool has_extension() const
+  {
+    return !this->get_filename_fragment(filename_fragment::extension).empty();
+  }
+
+  bool is_absolute() const
+  {
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+    return this->has_root_name() && this->has_root_directory();
+#  else
+    // For CYGWIN, root_name (i.e. //host or /cygdrive/x) is not considered.
+    // Same as current GNU g++ implementation (9.3).
+    return this->has_root_directory();
+#  endif
+  }
+
+  bool is_relative() const { return !this->is_absolute(); }
+
+  // Iterators
+  // =========
+  inline iterator begin() const;
+  inline iterator end() const;
+
+  // Non-members
+  // ===========
+  friend inline bool operator==(const path& lhs, const path& rhs) noexcept
+  {
+    return lhs.compare(rhs) == 0;
+  }
+  friend inline bool operator!=(const path& lhs, const path& rhs) noexcept
+  {
+    return lhs.compare(rhs) != 0;
+  }
+  friend inline bool operator<(const path& lhs, const path& rhs) noexcept
+  {
+    return lhs.compare(rhs) < 0;
+  }
+  friend inline bool operator<=(const path& lhs, const path& rhs) noexcept
+  {
+    return lhs.compare(rhs) <= 0;
+  }
+  friend inline bool operator>(const path& lhs, const path& rhs) noexcept
+  {
+    return lhs.compare(rhs) > 0;
+  }
+  friend inline bool operator>=(const path& lhs, const path& rhs) noexcept
+  {
+    return lhs.compare(rhs) >= 0;
+  }
+
+  friend inline path operator/(const path& lhs, const path& rhs)
+  {
+    path result(lhs);
+    result /= rhs;
+
+    return result;
+  }
+
+  template <typename Char, typename Traits>
+  friend inline cm::enable_if_t<
+    (std::is_same<Char, path::value_type>::value &&
+     std::is_same<Traits, std::char_traits<path::value_type>>::value) ||
+      (std::is_same<Char, path::path_type::value_type>::value &&
+       std::is_same<Traits,
+                    std::char_traits<path::path_type::value_type>>::value),
+    std::basic_ostream<Char, Traits>&>
+  operator<<(std::basic_ostream<Char, Traits>& os, const path& p)
+  {
+    os << cm::quoted(p.string<Char, Traits>());
+    return os;
+  }
+
+  template <typename Char, typename Traits>
+  friend inline cm::enable_if_t<
+    (std::is_same<Char, path::value_type>::value &&
+     std::is_same<Traits, std::char_traits<path::value_type>>::value) ||
+      (std::is_same<Char, path::path_type::value_type>::value &&
+       std::is_same<Traits,
+                    std::char_traits<path::path_type::value_type>>::value),
+    std::basic_istream<Char, Traits>&>
+  operator>>(std::basic_istream<Char, Traits>& is, path& p)
+  {
+    std::basic_string<Char, Traits> tmp;
+    is >> cm::quoted(tmp);
+    p = tmp;
+    return is;
+  }
+
+private:
+  friend class iterator;
+  friend std::size_t hash_value(const path& p) noexcept;
+
+  path_type get_generic() const;
+
+  cm::string_view get_root_name() const;
+  cm::string_view get_root_directory() const;
+  cm::string_view get_relative_path() const;
+  cm::string_view get_parent_path() const;
+  cm::string_view get_filename() const;
+  cm::string_view get_filename_fragment(filename_fragment fragment) const;
+
+  int compare_path(cm::string_view str) const;
+
+  path_type path_;
+#  if defined(_WIN32) && !defined(__CYGWIN__)
+  mutable string_type native_path_;
+#  endif
+};
+
+class path::iterator
+{
+public:
+  using iterator_category = std::bidirectional_iterator_tag;
+
+  using value_type = path;
+  using difference_type = std::ptrdiff_t;
+  using pointer = const path*;
+  using reference = const path&;
+
+  iterator();
+  iterator(const iterator& other);
+
+  ~iterator();
+
+  iterator& operator=(const iterator& other);
+
+  reference operator*() const { return this->path_element_; }
+
+  pointer operator->() const { return &this->path_element_; }
+
+  iterator& operator++();
+
+  iterator operator++(int)
+  {
+    iterator it(*this);
+    this->operator++();
+    return it;
+  }
+
+  iterator& operator--();
+
+  iterator operator--(int)
+  {
+    iterator it(*this);
+    this->operator--();
+    return it;
+  }
+
+private:
+  friend class path;
+  friend bool operator==(const iterator&, const iterator&);
+
+  iterator(const path* p, bool at_end = false);
+
+  const path* path_;
+  std::unique_ptr<internals::path_parser> parser_;
+  path path_element_;
+};
+
+inline path::iterator path::begin() const
+{
+  return iterator(this);
+}
+inline path::iterator path::end() const
+{
+  return iterator(this, true);
+}
+
+bool operator==(const path::iterator& lhs, const path::iterator& rhs);
+
+inline bool operator!=(const path::iterator& lhs, const path::iterator& rhs)
+{
+  return !(lhs == rhs);
+}
+
+// Non-member functions
+// ====================
+inline void swap(path& lhs, path& rhs) noexcept
+{
+  lhs.swap(rhs);
+}
+
+std::size_t hash_value(const path& p) noexcept;
+
+#endif
+
+} // namespace filesystem
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/iomanip b/Utilities/std/cm/iomanip
new file mode 100644
index 0000000..6f68530
--- /dev/null
+++ b/Utilities/std/cm/iomanip
@@ -0,0 +1,183 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cm_iomanip
+#define cm_iomanip
+
+#include <iomanip> // IWYU pragma: export
+#if __cplusplus < 201402L || defined(_MSVC_LANG) && _MSVC_LANG < 201402L
+#  include <ios>
+#  include <iostream>
+#  include <sstream>
+#  include <string>
+#  include <type_traits>
+#endif
+#if __cplusplus < 201703L || defined(_MSVC_LANG) && _MSVC_LANG < 201703L
+#  include <cm/string_view>
+#endif
+
+namespace cm {
+
+#if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
+
+using std::quoted;
+
+#  if __cplusplus < 201703L || defined(_MSVC_LANG) && _MSVC_LANG < 201703L
+
+inline auto quoted(cm::string_view str, char delim = '"', char escape = '\\')
+{
+  return std::quoted(static_cast<std::string>(str), delim, escape);
+}
+
+#  endif
+
+#else
+
+namespace internals {
+
+// Struct for delimited strings.
+template <typename String, typename Char>
+struct quoted_string
+{
+  static_assert(std::is_reference<String>::value ||
+                  std::is_pointer<String>::value,
+                "String type must be pointer or reference");
+
+  quoted_string(String str, Char del, Char esc)
+    : string_(str)
+    , delim_{ del }
+    , escape_{ esc }
+  {
+  }
+
+  quoted_string& operator=(quoted_string&) = delete;
+
+  String string_;
+  Char delim_;
+  Char escape_;
+};
+
+template <>
+struct quoted_string<cm::string_view, char>
+{
+  quoted_string(cm::string_view str, char del, char esc)
+    : string_(str)
+    , delim_{ del }
+    , escape_{ esc }
+  {
+  }
+
+  quoted_string& operator=(quoted_string&) = delete;
+
+  cm::string_view string_;
+  char delim_;
+  char escape_;
+};
+
+template <typename Char, typename Traits>
+std::basic_ostream<Char, Traits>& operator<<(
+  std::basic_ostream<Char, Traits>& os,
+  const quoted_string<const Char*, Char>& str)
+{
+  std::basic_ostringstream<Char, Traits> ostr;
+  ostr << str.delim_;
+  for (const Char* c = str.string_; *c; ++c) {
+    if (*c == str.delim_ || *c == str.escape_)
+      ostr << str.escape_;
+    ostr << *c;
+  }
+  ostr << str.delim_;
+
+  return os << ostr.str();
+}
+
+template <typename Char, typename Traits, typename String>
+std::basic_ostream<Char, Traits>& operator<<(
+  std::basic_ostream<Char, Traits>& os, const quoted_string<String, Char>& str)
+{
+  std::basic_ostringstream<Char, Traits> ostr;
+  ostr << str.delim_;
+  for (auto c : str.string_) {
+    if (c == str.delim_ || c == str.escape_)
+      ostr << str.escape_;
+    ostr << c;
+  }
+  ostr << str.delim_;
+
+  return os << ostr.str();
+}
+
+template <typename Char, typename Traits, typename Alloc>
+std::basic_istream<Char, Traits>& operator>>(
+  std::basic_istream<Char, Traits>& is,
+  const quoted_string<std::basic_string<Char, Traits, Alloc>&, Char>& str)
+{
+  Char c;
+  is >> c;
+  if (!is.good())
+    return is;
+  if (c != str.delim_) {
+    is.unget();
+    is >> str.string_;
+    return is;
+  }
+  str.string_.clear();
+  std::ios_base::fmtflags flags =
+    is.flags(is.flags() & ~std::ios_base::skipws);
+  do {
+    is >> c;
+    if (!is.good())
+      break;
+    if (c == str.escape_) {
+      is >> c;
+      if (!is.good())
+        break;
+    } else if (c == str.delim_)
+      break;
+    str.string_ += c;
+  } while (true);
+  is.setf(flags);
+
+  return is;
+}
+}
+
+template <typename Char>
+inline internals::quoted_string<const Char*, Char> quoted(
+  const Char* str, Char delim = Char('"'), Char escape = Char('\\'))
+{
+  return internals::quoted_string<const Char*, Char>(str, delim, escape);
+}
+
+template <typename Char, typename Traits, typename Alloc>
+inline internals::quoted_string<const std::basic_string<Char, Traits, Alloc>&,
+                                Char>
+quoted(const std::basic_string<Char, Traits, Alloc>& str,
+       Char delim = Char('"'), Char escape = Char('\\'))
+{
+  return internals::quoted_string<
+    const std::basic_string<Char, Traits, Alloc>&, Char>(str, delim, escape);
+}
+
+template <typename Char, typename Traits, typename Alloc>
+inline internals::quoted_string<std::basic_string<Char, Traits, Alloc>&, Char>
+quoted(std::basic_string<Char, Traits, Alloc>& str, Char delim = Char('"'),
+       Char escape = Char('\\'))
+{
+  return internals::quoted_string<std::basic_string<Char, Traits, Alloc>&,
+                                  Char>(str, delim, escape);
+}
+
+inline internals::quoted_string<cm::string_view, char> quoted(
+  cm::string_view str, char delim = '"', char escape = '\\')
+{
+  return internals::quoted_string<cm::string_view, char>(str, delim, escape);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/memory b/Utilities/std/cm/memory
index dd0f822..5611f6b 100644
--- a/Utilities/std/cm/memory
+++ b/Utilities/std/cm/memory
@@ -6,7 +6,10 @@
 #ifndef cm_memory
 #define cm_memory
 
+#include "cmSTL.hxx" // IWYU pragma: keep
+
 #include <memory> // IWYU pragma: export
+
 #if !defined(CMake_HAVE_CXX_MAKE_UNIQUE)
 #  include <cstddef>
 #  include <type_traits>
diff --git a/Utilities/std/cmSTL.hxx.in b/Utilities/std/cmSTL.hxx.in
new file mode 100644
index 0000000..9c8605c
--- /dev/null
+++ b/Utilities/std/cmSTL.hxx.in
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmSTL_hxx
+#define cmSTL_hxx
+
+/* Whether CMake is using its own STL implementation.  */
+#cmakedefine CMake_HAVE_CXX_MAKE_UNIQUE
+#cmakedefine CMake_HAVE_CXX_FILESYSTEM
+
+#endif
diff --git a/bootstrap b/bootstrap
index 68218d5..e6484ce 100755
--- a/bootstrap
+++ b/bootstrap
@@ -479,6 +479,7 @@
 fi
 
 CMAKE_STD_CXX_HEADERS="\
+  filesystem \
   memory \
   optional \
   shared_mutex \
@@ -486,6 +487,7 @@
   utility \
 "
 CMAKE_STD_CXX_SOURCES="\
+  fs_path \
   string_view \
 "
 
@@ -623,6 +625,8 @@
   --no-system-bzip2       use cmake-provided bzip2 library (default)
   --system-liblzma        use system-installed liblzma library
   --no-system-liblzma     use cmake-provided liblzma library (default)
+  --system-nghttp2        use system-installed nghttp2 library
+  --no-system-nghttp2     use cmake-provided nghttp2 library (default)
   --system-zstd           use system-installed zstd library
   --no-system-zstd        use cmake-provided zstd library (default)
   --system-libarchive     use system-installed libarchive library
@@ -870,10 +874,10 @@
   --init=*) cmake_init_file=`cmake_arg "$1"` ;;
   --system-libs) cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARIES=1" ;;
   --no-system-libs) cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARIES=0" ;;
-  --system-bzip2|--system-curl|--system-expat|--system-jsoncpp|--system-libarchive|--system-librhash|--system-zlib|--system-liblzma|--system-zstd|--system-libuv)
+  --system-bzip2|--system-curl|--system-expat|--system-jsoncpp|--system-libarchive|--system-librhash|--system-zlib|--system-liblzma|--system-nghttp2|--system-zstd|--system-libuv)
     lib=`cmake_arg "$1" "--system-"`
     cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARY_`cmake_toupper $lib`=1" ;;
-  --no-system-bzip2|--no-system-curl|--no-system-expat|--no-system-jsoncpp|--no-system-libarchive|--no-system-librhash|--no-system-zlib|--no-system-liblzma|--no-system-zstd|--no-system-libuv)
+  --no-system-bzip2|--no-system-curl|--no-system-expat|--no-system-jsoncpp|--no-system-libarchive|--no-system-librhash|--no-system-zlib|--no-system-liblzma|--no-system-nghttp2|--no-system-zstd|--no-system-libuv)
     lib=`cmake_arg "$1" "--no-system-"`
     cmake_bootstrap_system_libs="${cmake_bootstrap_system_libs} -DCMAKE_USE_SYSTEM_LIBRARY_`cmake_toupper $lib`=0" ;;
   --bootstrap-system-libuv) bootstrap_system_libuv="1" ;;
@@ -1252,7 +1256,7 @@
 #-----------------------------------------------------------------------------
 # Test CXX features
 
-cmake_cxx_features="make_unique"
+cmake_cxx_features="make_unique filesystem"
 
 for feature in ${cmake_cxx_features}; do
   eval "cmake_have_cxx_${feature}=0"
@@ -1272,6 +1276,9 @@
   fi
 done
 
+cmake_generate_file "${cmake_bootstrap_dir}/cmSTL.hxx" ""
+
+
 #-----------------------------------------------------------------------------
 # Test Make