Merge topic 'gtest_discover_tests_cross_compile_support'

3b4838b57f GoogleTest: Add tests for MultiConfig discovery in PRE_TEST mode
1ba4cb565e GoogleTest: Parameterize tests to check PRE_TEST/POST_BUILD discovery mode
75e82a13db GoogleTest: Add new DISCOVERY_MODE option to gtest_discover_tests
889a7146ff GoogleTestAddTests: Refactor into callable method

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4078
diff --git a/Help/command/install.rst b/Help/command/install.rst
index abf6b17..cf04eda 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -644,6 +644,13 @@
 ``(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?`` to be exported, when
 policy :policy:`CMP0022` is ``NEW``.
 
+.. note::
+  The installed ``<export-name>.cmake`` file may come with additional
+  per-configuration ``<export-name>-*.cmake`` files to be loaded by
+  globbing.  Do not use an export name that is the same as the package
+  name in combination with installing a ``<package-name>-config.cmake``
+  file or the latter may be incorrectly matched by the glob and loaded.
+
 When a ``COMPONENT`` option is given, the listed ``<component>`` implicitly
 depends on all components mentioned in the export set. The exported
 ``<name>.cmake`` file will require each of the exported components to be
diff --git a/Help/generator/Ninja Multi-Config.rst b/Help/generator/Ninja Multi-Config.rst
index 1f68535..f480eb8 100644
--- a/Help/generator/Ninja Multi-Config.rst
+++ b/Help/generator/Ninja Multi-Config.rst
@@ -33,53 +33,19 @@
 The ``Ninja Multi-Config`` generator recognizes the following variables:
 
 :variable:`CMAKE_CONFIGURATION_TYPES`
-  Specifies the total set of configurations to build. See the variable's
-  documentation for more information.
+  Specifies the total set of configurations to build.
 
 :variable:`CMAKE_CROSS_CONFIGS`
   Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
   configurations available from all ``build-<Config>.ninja`` files.
-  This variable activates cross-config mode.
-  Targets from each config specified in this variable can be built from any
-  ``build-<Config>.ninja`` file. Custom commands will use the configuration
-  native to ``build-<Config>.ninja``. If it is set to ``all``, all
-  configurations from :variable:`CMAKE_CONFIGURATION_TYPES` are cross-configs.
-  If it is not specified, or empty, each ``build-<Config>.ninja`` file will
-  only contain build rules for its own configuration.
-
-  The value of this variable must be a subset of
-  :variable:`CMAKE_CONFIGURATION_TYPES`.
 
 :variable:`CMAKE_DEFAULT_BUILD_TYPE`
-  Specifies the configuration to use by default in a ``build.ninja`` file. If
-  this variable is specified, ``build.ninja`` uses build rules from
-  ``build-<Config>.ninja`` by default. All custom commands are executed with
-  this configuration. If the variable is not specified, the first item from
-  :variable:`CMAKE_CONFIGURATION_TYPES` is used instead.
-
-  The value of this variable must be one of the items from
-  :variable:`CMAKE_CONFIGURATION_TYPES`.
+  Specifies the configuration to use by default in a ``build.ninja`` file.
 
 :variable:`CMAKE_DEFAULT_CONFIGS`
   Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
   configurations to build for a target in ``build.ninja``
-  if no ``:<Config>`` suffix is specified. If it is set to ``all``, all
-  configurations from :variable:`CMAKE_CROSS_CONFIGS` are used. If
-  it is not specified, it defaults to
-  :variable:`CMAKE_DEFAULT_BUILD_TYPE`.
-
-  For example, if you set
-  :variable:`CMAKE_DEFAULT_BUILD_TYPE` to ``Release``, but
-  set :variable:`CMAKE_DEFAULT_CONFIGS` to ``Debug`` or ``all``,
-  all ``<target>`` aliases in ``build.ninja`` will resolve to
-  ``<target>:Debug`` or ``<target>:all``, but custom commands will still use
-  the ``Release`` configuration.
-
-  The value of this variable must be a subset of
-  :variable:`CMAKE_CROSS_CONFIGS` or be the same as
-  :variable:`CMAKE_DEFAULT_BUILD_TYPE`. It must not be
-  specified if :variable:`CMAKE_DEFAULT_BUILD_TYPE` or
-  :variable:`CMAKE_CROSS_CONFIGS` is not used.
+  if no ``:<Config>`` suffix is specified.
 
 Consider the following example:
 
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index c256250..08d59e7 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -51,6 +51,14 @@
 to determine whether to report an error on use of deprecated macros or
 functions.
 
+Policies Introduced by CMake 3.18
+=================================
+
+.. toctree::
+   :maxdepth: 1
+
+   CMP0103: Multiple export() with same FILE without APPEND is not allowed. </policy/CMP0103>
+
 Policies Introduced by CMake 3.17
 =================================
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index e552377..a2bbdcd 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -127,6 +127,7 @@
    /prop_tgt/ARCHIVE_OUTPUT_DIRECTORY
    /prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG
    /prop_tgt/ARCHIVE_OUTPUT_NAME
+   /prop_tgt/PCH_WARN_INVALID
    /prop_tgt/AUTOGEN_BUILD_DIR
    /prop_tgt/AUTOGEN_ORIGIN_DEPENDS
    /prop_tgt/AUTOGEN_PARALLEL
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index c271024..62c301c 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -438,6 +438,7 @@
    /variable/CMAKE_OSX_ARCHITECTURES
    /variable/CMAKE_OSX_DEPLOYMENT_TARGET
    /variable/CMAKE_OSX_SYSROOT
+   /variable/CMAKE_PCH_WARN_INVALID
    /variable/CMAKE_PDB_OUTPUT_DIRECTORY
    /variable/CMAKE_PDB_OUTPUT_DIRECTORY_CONFIG
    /variable/CMAKE_POSITION_INDEPENDENT_CODE
diff --git a/Help/policy/CMP0103.rst b/Help/policy/CMP0103.rst
new file mode 100644
index 0000000..223e0cb
--- /dev/null
+++ b/Help/policy/CMP0103.rst
@@ -0,0 +1,22 @@
+CMP0103
+-------
+
+Multiple calls to :command:`export` command with same ``FILE`` without
+``APPEND`` is no longer allowed.
+
+In CMake 3.17 and below, multiple calls to :command:`export` command with the
+same ``FILE`` without ``APPEND`` are accepted silently but only the last
+occurrence is taken into account during the generation.
+
+The ``OLD`` behavior for this policy is to ignore the multiple occurrences of
+ :command:`export` command except the last one.
+
+The ``NEW`` behavior of this policy is to raise an error on second call to
+:command:`export` command with same ``FILE`` without ``APPEND``.
+
+This policy was introduced in CMake version 3.18.  CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_tgt/PCH_WARN_INVALID.rst b/Help/prop_tgt/PCH_WARN_INVALID.rst
new file mode 100644
index 0000000..36ec348
--- /dev/null
+++ b/Help/prop_tgt/PCH_WARN_INVALID.rst
@@ -0,0 +1,8 @@
+PCH_WARN_INVALID
+----------------
+
+When this property is set to true, the precompile header compiler options
+will contain a compiler flag wich should warn about invalid precompiled
+headers e.g. ``-Winvalid-pch`` for GNU compiler.
+
+The defalut value is ``ON``.
diff --git a/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
index 0e182cf..c32b4de 100644
--- a/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
+++ b/Help/prop_tgt/XCODE_GENERATE_SCHEME.rst
@@ -38,3 +38,4 @@
 - :prop_tgt:`XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING`
 - :prop_tgt:`XCODE_SCHEME_ENVIRONMENT`
 - :prop_tgt:`XCODE_SCHEME_EXECUTABLE`
+- :prop_tgt:`XCODE_SCHEME_WORKING_DIRECTORY`
diff --git a/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst b/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst
index 7ffa74b..f538f1d 100644
--- a/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst
+++ b/Help/prop_tgt/XCODE_SCHEME_WORKING_DIRECTORY.rst
@@ -1,8 +1,8 @@
 XCODE_SCHEME_WORKING_DIRECTORY
 ------------------------------
 
-Specify the ``Working Directory`` a of the `Run` and `Profile`
-action in the generated Xcode scheme. In case the value contains
+Specify the ``Working Directory`` of the *Run* and *Profile*
+actions in the generated Xcode scheme. In case the value contains
 generator expressions those are evaluated.
 
 This property is initialized by the value of the variable
diff --git a/Help/release/dev/export-multiple-calls.rst b/Help/release/dev/export-multiple-calls.rst
new file mode 100644
index 0000000..00372ce
--- /dev/null
+++ b/Help/release/dev/export-multiple-calls.rst
@@ -0,0 +1,5 @@
+export-multiple-calls
+---------------------
+
+* The :command:`export` command now raise an error if used multiple times with
+  same ``FILE`` without ``APPEND``. See policy :policy:`CMP0103`.
diff --git a/Help/release/dev/pch-warn-invalid.rst b/Help/release/dev/pch-warn-invalid.rst
new file mode 100644
index 0000000..5fa3de7
--- /dev/null
+++ b/Help/release/dev/pch-warn-invalid.rst
@@ -0,0 +1,6 @@
+pch-warn-invalid
+----------------
+
+* The :variable:`CMAKE_PCH_WARN_INVALID` variable was added to initialize the
+  :prop_tgt:`PCH_WARN_INVALID` target property to allow the removal of the
+  precompiled header invalid warning.
diff --git a/Help/variable/CMAKE_CROSS_CONFIGS.rst b/Help/variable/CMAKE_CROSS_CONFIGS.rst
index c850af2..94157f3 100644
--- a/Help/variable/CMAKE_CROSS_CONFIGS.rst
+++ b/Help/variable/CMAKE_CROSS_CONFIGS.rst
@@ -3,5 +3,13 @@
 
 Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of
 configurations available from all ``build-<Config>.ninja`` files in the
-:generator:`Ninja Multi-Config` generator. See the generator's
-documentation for more details.
+:generator:`Ninja Multi-Config` generator.  This variable activates
+cross-config mode. Targets from each config specified in this variable can be
+built from any ``build-<Config>.ninja`` file. Custom commands will use the
+configuration native to ``build-<Config>.ninja``. If it is set to ``all``, all
+configurations from :variable:`CMAKE_CONFIGURATION_TYPES` are cross-configs. If
+it is not specified, or empty, each ``build-<Config>.ninja`` file will only
+contain build rules for its own configuration.
+
+The value of this variable must be a subset of
+:variable:`CMAKE_CONFIGURATION_TYPES`.
diff --git a/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst b/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst
index 62ee0d2..aa4f82d 100644
--- a/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst
+++ b/Help/variable/CMAKE_DEFAULT_BUILD_TYPE.rst
@@ -2,5 +2,11 @@
 ------------------------
 
 Specifies the configuration to use by default in a ``build.ninja`` file in the
-:generator:`Ninja Multi-Config` generator. See the generator's documentation
-for more details.
+:generator:`Ninja Multi-Config` generator. If this variable is specified,
+``build.ninja`` uses build rules from ``build-<Config>.ninja`` by default. All
+custom commands are executed with this configuration. If the variable is not
+specified, the first item from :variable:`CMAKE_CONFIGURATION_TYPES` is used
+instead.
+
+The value of this variable must be one of the items from
+:variable:`CMAKE_CONFIGURATION_TYPES`.
diff --git a/Help/variable/CMAKE_DEFAULT_CONFIGS.rst b/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
index 86d8a5a..84c642a 100644
--- a/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
+++ b/Help/variable/CMAKE_DEFAULT_CONFIGS.rst
@@ -3,5 +3,17 @@
 
 Specifies a :ref:`semicolon-separated list <CMake Language Lists>` of configurations
 to build for a target in ``build.ninja`` if no ``:<Config>`` suffix is specified in
-the :generator:`Ninja Multi-Config` generator.
-See the generator's documentation for more details.
+the :generator:`Ninja Multi-Config` generator. If it is set to ``all``, all
+configurations from :variable:`CMAKE_CROSS_CONFIGS` are used. If it is not
+specified, it defaults to :variable:`CMAKE_DEFAULT_BUILD_TYPE`.
+
+For example, if you set :variable:`CMAKE_DEFAULT_BUILD_TYPE` to ``Release``,
+but set :variable:`CMAKE_DEFAULT_CONFIGS` to ``Debug`` or ``all``, all
+``<target>`` aliases in ``build.ninja`` will resolve to ``<target>:Debug`` or
+``<target>:all``, but custom commands will still use the ``Release``
+configuration.
+
+The value of this variable must be a subset of :variable:`CMAKE_CROSS_CONFIGS`
+or be the same as :variable:`CMAKE_DEFAULT_BUILD_TYPE`. It must not be
+specified if :variable:`CMAKE_DEFAULT_BUILD_TYPE` or
+:variable:`CMAKE_CROSS_CONFIGS` is not used.
diff --git a/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst b/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
index a99c108..34524d1 100644
--- a/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
+++ b/Help/variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH.rst
@@ -9,5 +9,5 @@
 contain linked library files.  The directories are appended after the
 value of the :prop_tgt:`INSTALL_RPATH` target property.
 
-This varibale is used to initialize the target property
+This variable is used to initialize the target property
 :prop_tgt:`INSTALL_RPATH_USE_LINK_PATH` for all targets.
diff --git a/Help/variable/CMAKE_PCH_WARN_INVALID.rst b/Help/variable/CMAKE_PCH_WARN_INVALID.rst
new file mode 100644
index 0000000..e152abd
--- /dev/null
+++ b/Help/variable/CMAKE_PCH_WARN_INVALID.rst
@@ -0,0 +1,5 @@
+CMAKE_PCH_WARN_INVALID
+----------------------
+
+This variable is used to initialize the :prop_tgt:`PCH_WARN_INVALID`
+property of targets when they are created.
diff --git a/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst b/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst
index cc690f7..5bb7907 100644
--- a/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst
+++ b/Help/variable/CMAKE_XCODE_SCHEME_WORKING_DIRECTORY.rst
@@ -1,8 +1,8 @@
 CMAKE_XCODE_SCHEME_WORKING_DIRECTORY
 ------------------------------------
 
-Specify the ``Working Directory`` a of the `Run` and `Profile`
-action in the generated Xcode scheme.
+Specify the ``Working Directory`` of the *Run* and *Profile*
+actions in the generated Xcode scheme.
 
 This variable initializes the
 :prop_tgt:`XCODE_SCHEME_WORKING_DIRECTORY`
diff --git a/Modules/CMakeASMInformation.cmake b/Modules/CMakeASMInformation.cmake
index 6b73730..03195cc 100644
--- a/Modules/CMakeASMInformation.cmake
+++ b/Modules/CMakeASMInformation.cmake
@@ -76,12 +76,12 @@
 if(NOT CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY)
   set(CMAKE_ASM${ASM_DIALECT}_CREATE_STATIC_LIBRARY
       "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS> "
-      "<CMAKE_RANLIB> <TARGET> ")
+      "<CMAKE_RANLIB> <TARGET>")
 endif()
 
 if(NOT CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE)
   set(CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE
-    "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endif()
 
 if(NOT CMAKE_EXECUTABLE_RUNTIME_ASM${ASM_DIALECT}_FLAG)
diff --git a/Modules/CMakeASM_MASMInformation.cmake b/Modules/CMakeASM_MASMInformation.cmake
index 9f7e934..6d1e174 100644
--- a/Modules/CMakeASM_MASMInformation.cmake
+++ b/Modules/CMakeASM_MASMInformation.cmake
@@ -8,7 +8,7 @@
 
 set(CMAKE_ASM${ASM_DIALECT}_SOURCE_FILE_EXTENSIONS asm)
 
-set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /c  /Fo <OBJECT> <SOURCE>")
+set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OBJECT "<CMAKE_ASM${ASM_DIALECT}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /c /Fo <OBJECT> <SOURCE>")
 
 # The ASM_MASM compiler id for this compiler is "MSVC", so fill out the runtime library table.
 set(CMAKE_ASM${ASM_DIALECT}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         "")
diff --git a/Modules/CMakeCInformation.cmake b/Modules/CMakeCInformation.cmake
index 1e08bb7..f6d620f 100644
--- a/Modules/CMakeCInformation.cmake
+++ b/Modules/CMakeCInformation.cmake
@@ -161,7 +161,7 @@
   set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_C_ARCHIVE_APPEND)
-  set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> q  <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_C_ARCHIVE_FINISH)
   set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
@@ -170,12 +170,12 @@
 # compile a C file into an object file
 if(NOT CMAKE_C_COMPILE_OBJECT)
   set(CMAKE_C_COMPILE_OBJECT
-    "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>   -c <SOURCE>")
+    "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
 endif()
 
 if(NOT CMAKE_C_LINK_EXECUTABLE)
   set(CMAKE_C_LINK_EXECUTABLE
-    "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endif()
 
 if(NOT CMAKE_EXECUTABLE_RUNTIME_C_FLAG)
diff --git a/Modules/CMakeCUDAInformation.cmake b/Modules/CMakeCUDAInformation.cmake
index f31713e..f7eb4a7 100644
--- a/Modules/CMakeCUDAInformation.cmake
+++ b/Modules/CMakeCUDAInformation.cmake
@@ -129,7 +129,7 @@
   set(CMAKE_CUDA_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_CUDA_ARCHIVE_APPEND)
-  set(CMAKE_CUDA_ARCHIVE_APPEND "<CMAKE_AR> q  <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_CUDA_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_CUDA_ARCHIVE_FINISH)
   set(CMAKE_CUDA_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
diff --git a/Modules/CMakeCXXInformation.cmake b/Modules/CMakeCXXInformation.cmake
index da7440a..dbb4366 100644
--- a/Modules/CMakeCXXInformation.cmake
+++ b/Modules/CMakeCXXInformation.cmake
@@ -258,7 +258,7 @@
   set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_CXX_ARCHIVE_APPEND)
-  set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> q  <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_CXX_ARCHIVE_FINISH)
   set(CMAKE_CXX_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
@@ -267,12 +267,12 @@
 # compile a C++ file into an object file
 if(NOT CMAKE_CXX_COMPILE_OBJECT)
   set(CMAKE_CXX_COMPILE_OBJECT
-    "<CMAKE_CXX_COMPILER>  <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+    "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
 endif()
 
 if(NOT CMAKE_CXX_LINK_EXECUTABLE)
   set(CMAKE_CXX_LINK_EXECUTABLE
-    "<CMAKE_CXX_COMPILER>  <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endif()
 
 mark_as_advanced(
diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake
index 812f032..9ebaa6c 100644
--- a/Modules/CMakeDetermineCompilerId.cmake
+++ b/Modules/CMakeDetermineCompilerId.cmake
@@ -128,7 +128,7 @@
     set(CMAKE_EXECUTABLE_FORMAT "Unknown" CACHE INTERNAL "Executable file format")
   endif()
 
-  if(CMAKE_GENERATOR STREQUAL "Ninja" AND MSVC_${lang}_ARCHITECTURE_ID)
+  if(CMAKE_GENERATOR MATCHES "^Ninja" AND MSVC_${lang}_ARCHITECTURE_ID)
     foreach(userflags "${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}" "")
       CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX(${lang} "${userflags}")
     endforeach()
@@ -246,8 +246,10 @@
     set(id_platform ${CMAKE_VS_PLATFORM_NAME})
     set(id_lang "${lang}")
     set(id_PostBuildEvent_Command "")
-    if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^([Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?|[Cc][Ll][Aa][Nn][Gg][Cc][Ll])$")
+    if(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Ll][Ll][Vv][Mm](_v[0-9]+(_xp)?)?$")
       set(id_cl_var "ClangClExecutable")
+    elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "^[Cc][Ll][Aa][Nn][Gg][Cc][Ll]$")
+      set(id_cl "$(CLToolExe)")
     elseif(CMAKE_VS_PLATFORM_TOOLSET MATCHES "v[0-9]+_clang_.*")
       set(id_cl clang.exe)
     else()
diff --git a/Modules/CMakeFortranInformation.cmake b/Modules/CMakeFortranInformation.cmake
index e80716b..9a4ce63 100644
--- a/Modules/CMakeFortranInformation.cmake
+++ b/Modules/CMakeFortranInformation.cmake
@@ -193,7 +193,7 @@
   set(CMAKE_Fortran_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_Fortran_ARCHIVE_APPEND)
-  set(CMAKE_Fortran_ARCHIVE_APPEND "<CMAKE_AR> q  <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_Fortran_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_Fortran_ARCHIVE_FINISH)
   set(CMAKE_Fortran_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
@@ -209,7 +209,7 @@
 # link a fortran program
 if(NOT CMAKE_Fortran_LINK_EXECUTABLE)
   set(CMAKE_Fortran_LINK_EXECUTABLE
-    "<CMAKE_Fortran_COMPILER> <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_Fortran_COMPILER> <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endif()
 
 if(CMAKE_Fortran_STANDARD_LIBRARIES_INIT)
diff --git a/Modules/CMakeOBJCInformation.cmake b/Modules/CMakeOBJCInformation.cmake
index 15a3311..b3da82d 100644
--- a/Modules/CMakeOBJCInformation.cmake
+++ b/Modules/CMakeOBJCInformation.cmake
@@ -161,7 +161,7 @@
   set(CMAKE_OBJC_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_OBJC_ARCHIVE_APPEND)
-  set(CMAKE_OBJC_ARCHIVE_APPEND "<CMAKE_AR> q  <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_OBJC_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_OBJC_ARCHIVE_FINISH)
   set(CMAKE_OBJC_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
@@ -170,12 +170,12 @@
 # compile an Objective-C file into an object file
 if(NOT CMAKE_OBJC_COMPILE_OBJECT)
   set(CMAKE_OBJC_COMPILE_OBJECT
-    "<CMAKE_OBJC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -x objective-c -o <OBJECT>   -c <SOURCE>")
+    "<CMAKE_OBJC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -x objective-c -o <OBJECT> -c <SOURCE>")
 endif()
 
 if(NOT CMAKE_OBJC_LINK_EXECUTABLE)
   set(CMAKE_OBJC_LINK_EXECUTABLE
-    "<CMAKE_OBJC_COMPILER> <FLAGS> <CMAKE_OBJC_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_OBJC_COMPILER> <FLAGS> <CMAKE_OBJC_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endif()
 
 if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG)
diff --git a/Modules/CMakeOBJCXXInformation.cmake b/Modules/CMakeOBJCXXInformation.cmake
index cb349d7..71beb7f 100644
--- a/Modules/CMakeOBJCXXInformation.cmake
+++ b/Modules/CMakeOBJCXXInformation.cmake
@@ -254,7 +254,7 @@
   set(CMAKE_OBJCXX_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_OBJCXX_ARCHIVE_APPEND)
-  set(CMAKE_OBJCXX_ARCHIVE_APPEND "<CMAKE_AR> q  <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_OBJCXX_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
 endif()
 if(NOT DEFINED CMAKE_OBJCXX_ARCHIVE_FINISH)
   set(CMAKE_OBJCXX_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
@@ -263,12 +263,12 @@
 # compile an Objective-C++ file into an object file
 if(NOT CMAKE_OBJCXX_COMPILE_OBJECT)
   set(CMAKE_OBJCXX_COMPILE_OBJECT
-    "<CMAKE_OBJCXX_COMPILER>  <DEFINES> <INCLUDES> <FLAGS> -x objective-c++ -o <OBJECT> -c <SOURCE>")
+    "<CMAKE_OBJCXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -x objective-c++ -o <OBJECT> -c <SOURCE>")
 endif()
 
 if(NOT CMAKE_OBJCXX_LINK_EXECUTABLE)
   set(CMAKE_OBJCXX_LINK_EXECUTABLE
-    "<CMAKE_OBJCXX_COMPILER>  <FLAGS> <CMAKE_OBJCXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_OBJCXX_COMPILER> <FLAGS> <CMAKE_OBJCXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endif()
 
 mark_as_advanced(
diff --git a/Modules/CheckIPOSupported.cmake b/Modules/CheckIPOSupported.cmake
index 0d6ad20..90a9f61 100644
--- a/Modules/CheckIPOSupported.cmake
+++ b/Modules/CheckIPOSupported.cmake
@@ -113,7 +113,7 @@
   endforeach()
 
   try_compile(
-      result
+      _IPO_LANGUAGE_CHECK_RESULT
       "${bindir}"
       "${srcdir}"
       "${TRY_COMPILE_PROJECT_NAME}"
@@ -122,8 +122,10 @@
       "-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON"
       OUTPUT_VARIABLE output
   )
+  set(_IPO_LANGUAGE_CHECK_RESULT "${_IPO_LANGUAGE_CHECK_RESULT}")
+  unset(_IPO_LANGUAGE_CHECK_RESULT CACHE)
 
-  if(NOT result)
+  if(NOT _IPO_LANGUAGE_CHECK_RESULT)
     file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
       "${language} compiler IPO check failed with the following output:\n"
       "${output}\n")
diff --git a/Modules/Compiler/GNU-ASM.cmake b/Modules/Compiler/GNU-ASM.cmake
index 4aa680f..3daa57d 100644
--- a/Modules/Compiler/GNU-ASM.cmake
+++ b/Modules/Compiler/GNU-ASM.cmake
@@ -8,5 +8,5 @@
 if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_MATCH STREQUAL "GNU assembler")
   set(CMAKE_DEPFILE_FLAGS_ASM${ASM_DIALECT} "--MD <DEPFILE>")
   set(CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE
-    "<CMAKE_LINKER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_LINKER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 endif()
diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake
index 1c050a2..3357a86 100644
--- a/Modules/Compiler/GNU.cmake
+++ b/Modules/Compiler/GNU.cmake
@@ -114,6 +114,7 @@
   if (NOT CMAKE_GENERATOR MATCHES "Xcode")
     set(CMAKE_PCH_PROLOGUE "#pragma GCC system_header")
   endif()
-  set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Winvalid-pch -include <PCH_HEADER>)
-  set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Winvalid-pch -x ${__pch_header_${lang}} -include <PCH_HEADER>)
+  set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
+  set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -include <PCH_HEADER>)
+  set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -x ${__pch_header_${lang}} -include <PCH_HEADER>)
 endmacro()
diff --git a/Modules/Compiler/Intel.cmake b/Modules/Compiler/Intel.cmake
index d895ed0..63a20af 100644
--- a/Modules/Compiler/Intel.cmake
+++ b/Modules/Compiler/Intel.cmake
@@ -37,7 +37,8 @@
     set(CMAKE_PCH_EXTENSION .pchi)
     set(CMAKE_LINK_PCH ON)
     set(CMAKE_PCH_EPILOGUE "#pragma hdrstop")
-    set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Winvalid-pch -Wno-pch-messages -pch-use <PCH_FILE> -include <PCH_HEADER>)
-    set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Winvalid-pch -Wno-pch-messages -pch-create <PCH_FILE> -include <PCH_HEADER>)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_INVALID_PCH -Winvalid-pch)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_USE_PCH -Wno-pch-messages -pch-use <PCH_FILE> -include <PCH_HEADER>)
+    set(CMAKE_${lang}_COMPILE_OPTIONS_CREATE_PCH -Wno-pch-messages -pch-create <PCH_FILE> -include <PCH_HEADER>)
   endmacro()
 endif()
diff --git a/Modules/Compiler/QCC-CXX.cmake b/Modules/Compiler/QCC-CXX.cmake
index 0e7314a..42303f4 100644
--- a/Modules/Compiler/QCC-CXX.cmake
+++ b/Modules/Compiler/QCC-CXX.cmake
@@ -10,6 +10,6 @@
   "<CMAKE_CXX_COMPILER> -lang-c++ <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
 
 set(CMAKE_CXX_LINK_EXECUTABLE
-  "<CMAKE_CXX_COMPILER> -lang-c++ <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+  "<CMAKE_CXX_COMPILER> -lang-c++ <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 
 set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 3c52466..38d3bfa 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -1646,10 +1646,15 @@
 #  Prefix initialization
 # ------------------------------------------------------------------------
 
-set(Boost_LIB_PREFIX "")
-if ( (GHSMULTI AND Boost_USE_STATIC_LIBS) OR
-    (WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) )
+# Boost's static libraries use a "lib" prefix on DLL platforms
+# to distinguish them from the DLL import libraries.
+if (Boost_USE_STATIC_LIBS AND (
+    (WIN32 AND NOT CYGWIN)
+    OR GHSMULTI
+    ))
   set(Boost_LIB_PREFIX "lib")
+else()
+  set(Boost_LIB_PREFIX "")
 endif()
 
 if ( NOT Boost_NAMESPACE )
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index 92ee729..e42c206 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -241,6 +241,7 @@
 endif()
 
 set(MATLAB_VERSIONS_MAPPING
+  "R2020a=9.8"
   "R2019b=9.7"
   "R2019a=9.6"
   "R2018b=9.5"
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 6132693..018956b 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -191,8 +191,7 @@
 
 ``Python_FIND_STRATEGY``
   This variable defines how lookup will be done.
-  The ``Python_FIND_STRATEGY`` variable can be set to empty or one of the
-  following:
+  The ``Python_FIND_STRATEGY`` variable can be set to one of the following:
 
   * ``VERSION``: Try to find the most recent version in all specified
     locations.
@@ -205,8 +204,7 @@
 ``Python_FIND_REGISTRY``
   On Windows the ``Python_FIND_REGISTRY`` variable determine the order
   of preference between registry and environment variables.
-  the ``Python_FIND_REGISTRY`` variable can be set to empty or one of the
-  following:
+  the ``Python_FIND_REGISTRY`` variable can be set to one of the following:
 
   * ``FIRST``: Try to use registry before environment variables.
     This is the default.
@@ -216,8 +214,8 @@
 ``Python_FIND_FRAMEWORK``
   On macOS the ``Python_FIND_FRAMEWORK`` variable determine the order of
   preference between Apple-style and unix-style package components.
-  This variable can be set to empty or take same values as
-  :variable:`CMAKE_FIND_FRAMEWORK` variable.
+  This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
+  variable.
 
   .. note::
 
@@ -231,8 +229,8 @@
   ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
   is active (i.e. the ``activate`` script has been evaluated). In this case, it
   takes precedence over ``Python_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
-  variables.  The ``Python_FIND_VIRTUALENV`` variable can be set to empty or
-  one of the following:
+  variables.  The ``Python_FIND_VIRTUALENV`` variable can be set to one of the
+  following:
 
   * ``FIRST``: The virtual environment is used before any other standard
     paths to look-up for the interpreter. This is the default.
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index a40d7f7..68be3f9 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -321,7 +321,7 @@
 
   if (_${_PYTHON_PREFIX}_EXECUTABLE AND NOT CMAKE_CROSSCOMPILING)
     if (NAME STREQUAL "PREFIX")
-      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig; sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))"
+      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))\nexcept Exception:\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))"
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _values
                        ERROR_QUIET
@@ -332,16 +332,23 @@
         list (REMOVE_DUPLICATES _values)
       endif()
     elseif (NAME STREQUAL "INCLUDES")
-      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig; sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))"
+      if (WIN32)
+        set (_scheme "nt")
+      else()
+        set (_scheme "posix_prefix")
+      endif()
+      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))\nexcept Exception:\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))"
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _values
                        ERROR_QUIET
                        OUTPUT_STRIP_TRAILING_WHITESPACE)
       if (_result)
         unset (_values)
+      else()
+        list (REMOVE_DUPLICATES _values)
       endif()
     elseif (NAME STREQUAL "SOABI")
-      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '']))"
+      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '']))\nexcept Exception:\n   import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '']))"
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _soabi
                        ERROR_QUIET
@@ -349,14 +356,15 @@
       if (_result)
         unset (_values)
       else()
-        list (GET _soabi 0 _values)
-        if (NOT _values)
-          # try to compute SOABI from EXT_SUFFIX
-          list (GET _soabi 1 _values)
-          if (_values)
-            # clean-up: remove prefix character and suffix
-            string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
+        foreach (_item IN LISTS _soabi)
+          if (_item)
+            set (_values "${_item}")
+            break()
           endif()
+        endforeach()
+        if (_values)
+          # clean-up: remove prefix character and suffix
+          string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
         endif()
       endif()
     else()
@@ -364,7 +372,7 @@
       if (NAME STREQUAL "CONFIGDIR")
         set (config_flag "LIBPL")
       endif()
-      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_config_var('${config_flag}'))"
+      execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n   from distutils import sysconfig\n   sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\nexcept Exception:\n   import sysconfig\n   sys.stdout.write(sysconfig.get_config_var('${config_flag}'))"
                        RESULT_VARIABLE _result
                        OUTPUT_VARIABLE _values
                        ERROR_QUIET
@@ -392,6 +400,10 @@
     list (REMOVE_DUPLICATES _values)
   endif()
 
+  if (WIN32 AND NAME MATCHES "^(PREFIX|CONFIGDIR|INCLUDES)$")
+    file (TO_CMAKE_PATH "${_values}" _values)
+  endif()
+
   set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE)
 endfunction()
 
@@ -939,15 +951,15 @@
 
 # Compute search signature
 # This signature will be used to check validity of cached variables on new search
-set (_${_PYTHON_PREFIX}_SIGNATURE "${${_PYTHON_PREFIX}_ROOT_DIR}:${${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}")
+set (_${_PYTHON_PREFIX}_SIGNATURE "${${_PYTHON_PREFIX}_ROOT_DIR}:${_${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}")
 if (NOT WIN32)
   string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${${_PYTHON_PREFIX}_USE_STATIC_LIBS}:")
 endif()
 if (CMAKE_HOST_APPLE)
-  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${${_PYTHON_PREFIX}_FIND_FRAMEWORK}")
+  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_FRAMEWORK}")
 endif()
 if (CMAKE_HOST_WIN32)
-  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${${_PYTHON_PREFIX}_FIND_REGISTRY}")
+  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_REGISTRY}")
 endif()
 
 
@@ -1297,7 +1309,7 @@
 
       list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 1 ${_PYTHON_PREFIX}_VERSION_MAJOR)
       list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 2 ${_PYTHON_PREFIX}_VERSION_MINOR)
-      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATH)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATCH)
 
       list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH)
       set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})
@@ -1381,7 +1393,7 @@
         endif()
 
         # retrieve various package installation directories
-        execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))"
+        execute_process (COMMAND "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))\nexcept Exception:\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))"
                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
                         OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS
                         ERROR_QUIET)
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index 10fe211..15e1ce1 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -140,8 +140,7 @@
 
 ``Python2_FIND_STRATEGY``
   This variable defines how lookup will be done.
-  The ``Python2_FIND_STRATEGY`` variable can be set to empty or one of the
-  following:
+  The ``Python2_FIND_STRATEGY`` variable can be set to one of the following:
 
   * ``VERSION``: Try to find the most recent version in all specified
     locations.
@@ -154,8 +153,7 @@
 ``Python2_FIND_REGISTRY``
   On Windows the ``Python2_FIND_REGISTRY`` variable determine the order
   of preference between registry and environment variables.
-  the ``Python2_FIND_REGISTRY`` variable can be set to empty or one of the
-  following:
+  the ``Python2_FIND_REGISTRY`` variable can be set to one of the following:
 
   * ``FIRST``: Try to use registry before environment variables.
     This is the default.
@@ -165,8 +163,8 @@
 ``Python2_FIND_FRAMEWORK``
   On macOS the ``Python2_FIND_FRAMEWORK`` variable determine the order of
   preference between Apple-style and unix-style package components.
-  This variable can be set to empty or take same values as
-  :variable:`CMAKE_FIND_FRAMEWORK` variable.
+  This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
+  variable.
 
   .. note::
 
@@ -180,8 +178,8 @@
   ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
   is active (i.e. the ``activate`` script has been evaluated). In this case, it
   takes precedence over ``Python2_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
-  variables.  The ``Python2_FIND_VIRTUALENV`` variable can be set to empty or
-  one of the following:
+  variables.  The ``Python2_FIND_VIRTUALENV`` variable can be set to one of the
+  following:
 
   * ``FIRST``: The virtual environment is used before any other standard
     paths to look-up for the interpreter. This is the default.
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index 211f982..8135a1d 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -188,8 +188,7 @@
 
 ``Python3_FIND_STRATEGY``
   This variable defines how lookup will be done.
-  The ``Python3_FIND_STRATEGY`` variable can be set to empty or one of the
-  following:
+  The ``Python3_FIND_STRATEGY`` variable can be set to one of the following:
 
   * ``VERSION``: Try to find the most recent version in all specified
     locations.
@@ -202,8 +201,7 @@
 ``Python3_FIND_REGISTRY``
   On Windows the ``Python3_FIND_REGISTRY`` variable determine the order
   of preference between registry and environment variables.
-  The ``Python3_FIND_REGISTRY`` variable can be set to empty or one of the
-  following:
+  The ``Python3_FIND_REGISTRY`` variable can be set to one of the following:
 
   * ``FIRST``: Try to use registry before environment variables.
     This is the default.
@@ -213,8 +211,8 @@
 ``Python3_FIND_FRAMEWORK``
   On macOS the ``Python3_FIND_FRAMEWORK`` variable determine the order of
   preference between Apple-style and unix-style package components.
-  This variable can be set to empty or take same values as
-  :variable:`CMAKE_FIND_FRAMEWORK` variable.
+  This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
+  variable.
 
   .. note::
 
@@ -228,8 +226,8 @@
   ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
   is active (i.e. the ``activate`` script has been evaluated). In this case, it
   takes precedence over ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
-  variables.  The ``Python3_FIND_VIRTUALENV`` variable can be set to empty or
-  one of the following:
+  variables.  The ``Python3_FIND_VIRTUALENV`` variable can be set to one of the
+  following:
 
   * ``FIRST``: The virtual environment is used before any other standard
     paths to look-up for the interpreter. This is the default.
diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake
index 1e010bf..1bdee60 100644
--- a/Modules/FindRuby.cmake
+++ b/Modules/FindRuby.cmake
@@ -22,6 +22,9 @@
 
 It also determines what the name of the library is.
 
+Virtual environments such as RVM are handled as well, by passing
+the argument ``Ruby_FIND_VIRTUALENV``
+
 Result Variables
 ^^^^^^^^^^^^^^^^
 
@@ -49,6 +52,28 @@
 
 ``Ruby_INCLUDE_PATH``
   same as Ruby_INCLUDE_DIRS, only provided for compatibility reasons, don't use it
+
+Hints
+^^^^^
+
+``Ruby_ROOT_DIR``
+  Define the root directory of a Ruby installation.
+
+``Ruby_FIND_VIRTUALENV``
+  This variable defines the handling of virtual environments managed by
+  ``rvm``. It is meaningful only when a virtual environment
+  is active (i.e. the ``rvm`` script has been evaluated or at least the
+  ``MY_RUBY_HOME`` environment variable is set).
+  The ``Ruby_FIND_VIRTUALENV`` variable can be set to empty or
+  one of the following:
+
+  * ``FIRST``: The virtual environment is used before any other standard
+    paths to look-up for the interpreter. This is the default.
+  * ``ONLY``: Only the virtual environment is used to look-up for the
+    interpreter.
+  * ``STANDARD``: The virtual environment is not used to look-up for the
+    interpreter (assuming it isn't still in the PATH...)
+
 #]=======================================================================]
 
 # Backwards compatibility
@@ -121,14 +146,115 @@
   list(REMOVE_DUPLICATES _Ruby_POSSIBLE_EXECUTABLE_NAMES)
 endif()
 
-if(_Ruby_DEBUG_OUTPUT)
-  message("_Ruby_POSSIBLE_EXECUTABLE_NAMES=${_Ruby_POSSIBLE_EXECUTABLE_NAMES}")
+# virtual environments handling (eg RVM)
+if (DEFINED ENV{MY_RUBY_HOME})
+  if(_Ruby_DEBUG_OUTPUT)
+    message("My ruby home is defined: $ENV{MY_RUBY_HOME}")
+  endif()
+
+  if (DEFINED Ruby_FIND_VIRTUALENV)
+    if (NOT Ruby_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$")
+      message (AUTHOR_WARNING "FindRuby: ${Ruby_FIND_VIRTUALENV}: invalid value for 'Ruby_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.")
+      set (_Ruby_FIND_VIRTUALENV "FIRST")
+    else()
+      set (_Ruby_FIND_VIRTUALENV ${Ruby_FIND_VIRTUALENV})
+    endif()
+  else()
+    set (_Ruby_FIND_VIRTUALENV FIRST)
+  endif()
+else()
+  if (DEFINED Ruby_FIND_VIRTUALENV)
+    message("Environment variable MY_RUBY_HOME isn't set, defaulting back to Ruby_FIND_VIRTUALENV=STANDARD")
+  endif()
+  set (_Ruby_FIND_VIRTUALENV STANDARD)
 endif()
 
-find_program (Ruby_EXECUTABLE
-  NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
-  NAMES_PER_DIR
-  )
+if(_Ruby_DEBUG_OUTPUT)
+  message("_Ruby_POSSIBLE_EXECUTABLE_NAMES=${_Ruby_POSSIBLE_EXECUTABLE_NAMES}")
+  message("_Ruby_FIND_VIRTUALENV=${_Ruby_FIND_VIRTUALENV}")
+endif()
+
+function (_RUBY_VALIDATE_INTERPRETER)
+  if (NOT Ruby_EXECUTABLE)
+    return()
+  endif()
+
+  cmake_parse_arguments (PARSE_ARGV 0 _RVI "EXACT;CHECK_EXISTS" "" "")
+  if (_RVI_UNPARSED_ARGUMENTS)
+    set (expected_version ${_RVI_UNPARSED_ARGUMENTS})
+  else()
+    unset (expected_version)
+  endif()
+
+  if (_RVI_CHECK_EXISTS AND NOT EXISTS "${Ruby_EXECUTABLE}")
+    # interpreter does not exist anymore
+    set (_Ruby_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${Ruby_EXECUTABLE}\"")
+    set_property (CACHE Ruby_EXECUTABLE PROPERTY VALUE "Ruby_EXECUTABLE-NOTFOUND")
+    return()
+  endif()
+
+  # Check the version it returns
+  # executable found must have a specific version
+  execute_process (COMMAND "${Ruby_EXECUTABLE}" -e "puts RUBY_VERSION"
+                   RESULT_VARIABLE result
+                   OUTPUT_VARIABLE version
+                   ERROR_QUIET
+                   OUTPUT_STRIP_TRAILING_WHITESPACE)
+  if (result OR (_RVI_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
+    # interpreter not usable or has wrong major version
+    if (result)
+      set (_Ruby_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${Ruby_EXECUTABLE}\"")
+    else()
+      set (_Ruby_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${Ruby_EXECUTABLE}\"")
+    endif()
+    set_property (CACHE Ruby_EXECUTABLE PROPERTY VALUE "Ruby_EXECUTABLE-NOTFOUND")
+    return()
+  endif()
+
+endfunction()
+
+while(1)
+  # Virtual environments handling
+  if(_Ruby_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+    if(_Ruby_DEBUG_OUTPUT)
+      message("Inside Matches")
+    endif()
+    find_program (Ruby_EXECUTABLE
+                  NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
+                  NAMES_PER_DIR
+                  PATHS ENV MY_RUBY_HOME
+                  PATH_SUFFIXES bin Scripts
+                  NO_CMAKE_PATH
+                  NO_CMAKE_ENVIRONMENT_PATH
+                  NO_SYSTEM_ENVIRONMENT_PATH
+                  NO_CMAKE_SYSTEM_PATH)
+
+    if(_Ruby_DEBUG_OUTPUT)
+      message("Ruby_EXECUTABLE=${Ruby_EXECUTABLE}")
+    endif()
+
+    _RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION}})
+    if(Ruby_EXECUTABLE)
+      break()
+    endif()
+    if(NOT _Ruby_FIND_VIRTUALENV STREQUAL "ONLY")
+      break()
+    endif()
+  elseif(_Ruby_DEBUG_OUTPUT)
+    message("_Ruby_FIND_VIRTUALENV doesn't match: ${_Ruby_FIND_VIRTUALENV}")
+  endif()
+
+  # try using standard paths
+  find_program (Ruby_EXECUTABLE
+                NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
+                NAMES_PER_DIR)
+  _RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION})
+  if (Ruby_EXECUTABLE)
+    break()
+  endif()
+
+  break()
+endwhile()
 
 if(Ruby_EXECUTABLE AND NOT Ruby_VERSION_MAJOR)
   function(_RUBY_CONFIG_VAR RBVAR OUTVAR)
@@ -266,6 +392,8 @@
   set(_Ruby_NODOT_VERSION "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}${Ruby_VERSION_PATCH}")
 endif()
 
+# FIXME: Currently we require both the interpreter and development components to be found
+# in order to use either.  See issue #20474.
 find_path(Ruby_INCLUDE_DIR
   NAMES ruby.h
   HINTS
diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake
index 57ae446..5c8c196 100644
--- a/Modules/GetPrerequisites.cmake
+++ b/Modules/GetPrerequisites.cmake
@@ -531,7 +531,7 @@
       string(TOLOWER "$ENV{windir}" windir)
       file(TO_CMAKE_PATH "${windir}" windir)
 
-      if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-)[^/]+dll)")
+      if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
         set(is_system 1)
       endif()
 
@@ -559,7 +559,7 @@
           string(TOLOWER "${env_windir}" windir)
           string(TOLOWER "${env_sysdir}" sysroot)
 
-          if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-)[^/]+dll)")
+          if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-|vcruntime)[^/]+dll)")
             set(is_system 1)
           endif()
         endif()
@@ -601,7 +601,7 @@
 
   if(NOT is_embedded)
     if(NOT IS_ABSOLUTE "${resolved_file}")
-      if(lower MATCHES "^(msvc|api-ms-win-)[^/]+dll" AND is_system)
+      if(lower MATCHES "^(msvc|api-ms-win-|vcruntime)[^/]+dll" AND is_system)
         message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
       else()
         message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
diff --git a/Modules/Platform/Android-Common.cmake b/Modules/Platform/Android-Common.cmake
index 1affcd0..581fde4 100644
--- a/Modules/Platform/Android-Common.cmake
+++ b/Modules/Platform/Android-Common.cmake
@@ -73,7 +73,7 @@
       macro(__android_stl lang)
         # FIXME: Add a way to add project-wide language-specific compile-only flags.
         set(CMAKE_CXX_COMPILE_OBJECT
-          "<CMAKE_CXX_COMPILER>  <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE> -nostdinc++")
+          "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE> -nostdinc++")
         string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -nostdlib++")
       endmacro()
     else()
diff --git a/Modules/Platform/BlueGeneL.cmake b/Modules/Platform/BlueGeneL.cmake
index 082e46c..0ed9975 100644
--- a/Modules/Platform/BlueGeneL.cmake
+++ b/Modules/Platform/BlueGeneL.cmake
@@ -23,18 +23,18 @@
 
 if(CMAKE_COMPILER_IS_GNUCC)
   set(CMAKE_C_LINK_EXECUTABLE
-    "<CMAKE_C_COMPILER> -Wl,-relax <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES> -Wl,-lgcc,-lc -lnss_files -lnss_dns -lresolv")
+    "<CMAKE_C_COMPILER> -Wl,-relax <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-lgcc,-lc -lnss_files -lnss_dns -lresolv")
 else()
   # when using IBM xlc we probably don't want to link to -lgcc
   set(CMAKE_C_LINK_EXECUTABLE
-    "<CMAKE_C_COMPILER> -Wl,-relax <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES> -Wl,-lc -lnss_files -lnss_dns -lresolv")
+    "<CMAKE_C_COMPILER> -Wl,-relax <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-lc -lnss_files -lnss_dns -lresolv")
 endif()
 
 if(CMAKE_COMPILER_IS_GNUCXX)
   set(CMAKE_CXX_LINK_EXECUTABLE
-    "<CMAKE_CXX_COMPILER> -Wl,-relax <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES> -Wl,-lstdc++,-lgcc,-lc -lnss_files -lnss_dns -lresolv")
+    "<CMAKE_CXX_COMPILER> -Wl,-relax <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-lstdc++,-lgcc,-lc -lnss_files -lnss_dns -lresolv")
 else()
   # when using the IBM xlC we probably don't want to link to -lgcc
   set(CMAKE_CXX_LINK_EXECUTABLE
-    "<CMAKE_CXX_COMPILER> -Wl,-relax <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES> -Wl,-lstdc++,-lc -lnss_files -lnss_dns -lresolv")
+    "<CMAKE_CXX_COMPILER> -Wl,-relax <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -Wl,-lstdc++,-lc -lnss_files -lnss_dns -lresolv")
 endif()
diff --git a/Modules/Platform/BlueGeneP-base.cmake b/Modules/Platform/BlueGeneP-base.cmake
index fe95b42..7095dd8 100644
--- a/Modules/Platform/BlueGeneP-base.cmake
+++ b/Modules/Platform/BlueGeneP-base.cmake
@@ -97,7 +97,7 @@
   set(CMAKE_SHARED_LIBRARY_RUNTIME_${lang}_FLAG_SEP  ":") # : or empty
 
   set(BGP_${lang}_DEFAULT_EXE_FLAGS
-    "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> -Wl,-relax ${BGP_${lang}_DYNAMIC_EXE_FLAGS} ${BGP_${lang}_DEFAULT_EXE_FLAGS}")
 endmacro()
@@ -108,7 +108,7 @@
 #
 macro(__BlueGeneP_set_static_flags compiler_id lang)
   set(BGP_${lang}_DEFAULT_EXE_FLAGS
-    "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> -Wl,-relax ${BGP_${lang}_DEFAULT_EXE_FLAGS}")
 endmacro()
diff --git a/Modules/Platform/BlueGeneQ-base.cmake b/Modules/Platform/BlueGeneQ-base.cmake
index 5e56d8e..94cb0a8 100644
--- a/Modules/Platform/BlueGeneQ-base.cmake
+++ b/Modules/Platform/BlueGeneQ-base.cmake
@@ -101,7 +101,7 @@
   foreach(dir ${CMAKE_SYSTEM_INCLUDE_PATH})
     string(APPEND BGQ_SYSTEM_INCLUDES " -I${dir}")
   endforeach()
-  set(CMAKE_C_COMPILE_OBJECT   "<CMAKE_C_COMPILER>   <DEFINES> ${BGQ_SYSTEM_INCLUDES} <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+  set(CMAKE_C_COMPILE_OBJECT   "<CMAKE_C_COMPILER> <DEFINES> ${BGQ_SYSTEM_INCLUDES} <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
   set(CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> <DEFINES> ${BGQ_SYSTEM_INCLUDES} <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
 
   #
@@ -146,7 +146,7 @@
 
   # For dynamic executables, need to provide special BG/Q arguments.
   set(BGQ_${lang}_DEFAULT_EXE_FLAGS
-    "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> -Wl,-relax ${BGQ_${lang}_DYNAMIC_EXE_FLAGS} ${BGQ_${lang}_DEFAULT_EXE_FLAGS}")
 endmacro()
@@ -160,7 +160,7 @@
 
   # For static executables, use default link settings.
   set(BGQ_${lang}_DEFAULT_EXE_FLAGS
-    "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_LINK_EXECUTABLE
     "<CMAKE_${lang}_COMPILER> -Wl,-relax ${BGQ_${lang}_DEFAULT_EXE_FLAGS}")
 endmacro()
diff --git a/Modules/Platform/CYGWIN-GNU.cmake b/Modules/Platform/CYGWIN-GNU.cmake
index ca90712..4fa14ce 100644
--- a/Modules/Platform/CYGWIN-GNU.cmake
+++ b/Modules/Platform/CYGWIN-GNU.cmake
@@ -22,7 +22,7 @@
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
     "<CMAKE_${lang}_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_LINK_EXECUTABLE
-    "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+    "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
 
    # No -fPIC on cygwin
   set(CMAKE_${lang}_COMPILE_OPTIONS_PIC "")
diff --git a/Modules/Platform/HP-UX-HP-C.cmake b/Modules/Platform/HP-UX-HP-C.cmake
index 7610383..57ba2eb 100644
--- a/Modules/Platform/HP-UX-HP-C.cmake
+++ b/Modules/Platform/HP-UX-HP-C.cmake
@@ -3,4 +3,4 @@
 
 set(CMAKE_C_CREATE_PREPROCESSED_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
 set(CMAKE_C_CREATE_ASSEMBLY_SOURCE "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
-set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> -Aa -Ae <INCLUDES> <FLAGS> -o <OBJECT>   -c <SOURCE>")
+set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> <DEFINES> -Aa -Ae <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
diff --git a/Modules/Platform/Linux-como.cmake b/Modules/Platform/Linux-como.cmake
index d1550d2..f6db34c 100644
--- a/Modules/Platform/Linux-como.cmake
+++ b/Modules/Platform/Linux-como.cmake
@@ -11,7 +11,7 @@
 
 set(CMAKE_CXX_LINK_EXECUTABLE
     "<CMAKE_CXX_COMPILER> --prelink_objects <OBJECTS>"
-    "<CMAKE_CXX_COMPILER> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_CXX_COMPILER> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 
 set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "")
 set(CMAKE_SHARED_LIBRARY_C_FLAGS "")
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index 87ddfcd..018de4c 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -55,13 +55,13 @@
 
   # Create archiving rules to support large object file lists for static libraries.
   set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
-  set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q  <TARGET> <LINK_FLAGS> <OBJECTS>")
+  set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
   set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
     "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> <OBJECTS> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY})
   set(CMAKE_${lang}_LINK_EXECUTABLE
-    "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+    "<CMAKE_${lang}_COMPILER> -fuse-ld=lld-link -nostartfiles -nostdlib <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Xlinker /implib:<TARGET_IMPLIB> -Xlinker /pdb:<TARGET_PDB> -Xlinker /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
 
   if(NOT "${lang}" STREQUAL "ASM")
     set(CMAKE_${lang}_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded         -Xclang -flto-visibility-public-std -D_MT -Xclang --dependent-lib=libcmt)
@@ -134,14 +134,15 @@
     include(Platform/Windows-MSVC)
 
     # Feed the preprocessed rc file to llvm-rc
-    if(CMAKE_RC_COMPILER_INIT STREQUAL "llvm-rc")
-      if(DEFINED CMAKE_C_COMPILER)
+    if(CMAKE_RC_COMPILER_INIT MATCHES "llvm-rc")
+      if(DEFINED CMAKE_C_COMPILER_ID)
         set(CMAKE_RC_PREPROCESSOR CMAKE_C_COMPILER)
-      elseif(DEFINED CMAKE_CXX_COMPILER)
+      elseif(DEFINED CMAKE_CXX_COMPILER_ID)
         set(CMAKE_RC_PREPROCESSOR CMAKE_CXX_COMPILER)
       endif()
       if(DEFINED CMAKE_RC_PREPROCESSOR)
-        set(CMAKE_RC_COMPILE_OBJECT "${CMAKE_COMMAND} -E cmake_llvm_rc <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> -clang:-MD -clang:-MF -clang:<SOURCE>.d -E <SOURCE> -- <CMAKE_RC_COMPILER> <DEFINES> /fo <OBJECT> <OBJECT>.pp")
+        set(CMAKE_DEPFILE_FLAGS_RC "-clang:-MD -clang:-MF -clang:<DEPFILE>")
+        set(CMAKE_RC_COMPILE_OBJECT "${CMAKE_COMMAND} -E cmake_llvm_rc <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> -E <SOURCE> -- <CMAKE_RC_COMPILER> <DEFINES> /fo <OBJECT> <OBJECT>.pp")
         if(CMAKE_GENERATOR STREQUAL "Ninja")
           set(CMAKE_NINJA_CMCLDEPS_RC 0)
           set(CMAKE_NINJA_DEP_TYPE_RC gcc)
diff --git a/Modules/Platform/Windows-GNU.cmake b/Modules/Platform/Windows-GNU.cmake
index 38a8cf4..a2e3811 100644
--- a/Modules/Platform/Windows-GNU.cmake
+++ b/Modules/Platform/Windows-GNU.cmake
@@ -47,16 +47,12 @@
   set(__WINDOWS_GNU_LD_RESPONSE 0)
 endif()
 
-if(NOT CMAKE_GENERATOR_RC AND CMAKE_GENERATOR MATCHES "Unix Makefiles")
-  set(CMAKE_GENERATOR_RC windres)
-endif()
-
 macro(__windows_compiler_gnu lang)
 
   if(MSYS OR MINGW)
     # Create archiving rules to support large object file lists for static libraries.
     set(CMAKE_${lang}_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>")
-    set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q  <TARGET> <LINK_FLAGS> <OBJECTS>")
+    set(CMAKE_${lang}_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
     set(CMAKE_${lang}_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
 
     # Initialize C link type selection flags.  These flags are used when
@@ -108,7 +104,7 @@
   set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
     "<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
   set(CMAKE_${lang}_LINK_EXECUTABLE
-    "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
+    "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--out-implib,<TARGET_IMPLIB> ${CMAKE_GNULD_IMAGE_VERSION} <LINK_LIBRARIES>")
 
   list(APPEND CMAKE_${lang}_ABI_FILES "Platform/Windows-GNU-${lang}-ABI")
 
@@ -132,7 +128,7 @@
   endif()
 
   if(NOT CMAKE_RC_COMPILER_INIT AND NOT CMAKE_GENERATOR_RC)
-    set(CMAKE_RC_COMPILER_INIT windres)
+    set(CMAKE_RC_COMPILER_INIT ${_CMAKE_TOOLCHAIN_PREFIX}windres)
   endif()
 
   enable_language(RC)
diff --git a/Modules/Platform/Windows-df.cmake b/Modules/Platform/Windows-df.cmake
index f948914..8b824bc 100644
--- a/Modules/Platform/Windows-df.cmake
+++ b/Modules/Platform/Windows-df.cmake
@@ -13,7 +13,7 @@
 set(CMAKE_Fortran_MODDIR_FLAG "-module:")
 
 set(CMAKE_Fortran_CREATE_SHARED_LIBRARY
- "link ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE}  /out:<TARGET> /dll  <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+ "link ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} /out:<TARGET> /dll <LINK_FLAGS> <OBJECTS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
 
 set(CMAKE_Fortran_CREATE_SHARED_MODULE ${CMAKE_Fortran_CREATE_SHARED_LIBRARY})
 
@@ -22,7 +22,7 @@
 
 # compile a C++ file into an object file
 set(CMAKE_Fortran_COMPILE_OBJECT
-    "<CMAKE_Fortran_COMPILER>  ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /object:<OBJECT> <FLAGS> /compile_only <SOURCE>${CMAKE_END_TEMP_FILE}")
+    "<CMAKE_Fortran_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO} /object:<OBJECT> <FLAGS> /compile_only <SOURCE>${CMAKE_END_TEMP_FILE}")
 
 set(CMAKE_Fortran_LINK_EXECUTABLE
     "<CMAKE_Fortran_COMPILER> ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} <FLAGS> /exe:<TARGET> <OBJECTS> /link <CMAKE_Fortran_LINK_FLAGS> <LINK_FLAGS> <LINK_LIBRARIES>${CMAKE_END_TEMP_FILE}")
diff --git a/Modules/Platform/eCos.cmake b/Modules/Platform/eCos.cmake
index e1279ef..25db028 100644
--- a/Modules/Platform/eCos.cmake
+++ b/Modules/Platform/eCos.cmake
@@ -52,8 +52,8 @@
 add_definitions(-D__ECOS__=1 -D__ECOS=1)
 
 # special link commands for eCos executables
-set(CMAKE_CXX_LINK_EXECUTABLE  "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -nostdlib -nostartfiles -L${ECOS_LIBTARGET_DIRECTORY} -Ttarget.ld  <LINK_LIBRARIES>")
-set(CMAKE_C_LINK_EXECUTABLE    "<CMAKE_C_COMPILER>   <FLAGS> <CMAKE_C_LINK_FLAGS>   <LINK_FLAGS> <OBJECTS> -o <TARGET> -nostdlib -nostartfiles -L${ECOS_LIBTARGET_DIRECTORY} -Ttarget.ld  <LINK_LIBRARIES>")
+set(CMAKE_CXX_LINK_EXECUTABLE  "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -nostdlib -nostartfiles -L${ECOS_LIBTARGET_DIRECTORY} -Ttarget.ld <LINK_LIBRARIES>")
+set(CMAKE_C_LINK_EXECUTABLE    "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -nostdlib -nostartfiles -L${ECOS_LIBTARGET_DIRECTORY} -Ttarget.ld <LINK_LIBRARIES>")
 
 # eCos doesn't support shared libs
 set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
diff --git a/Modules/Platform/gas.cmake b/Modules/Platform/gas.cmake
index 7c659f2..8484076 100644
--- a/Modules/Platform/gas.cmake
+++ b/Modules/Platform/gas.cmake
@@ -11,7 +11,7 @@
       "<CMAKE_RANLIB> <TARGET> ")
 
 set(CMAKE_ASM${ASM_DIALECT}_LINK_EXECUTABLE
-    "<CMAKE_LINKER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")
+    "<CMAKE_LINKER> <FLAGS> <CMAKE_ASM${ASM_DIALECT}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
 
 # to be done
 set(CMAKE_ASM${ASM_DIALECT}_CREATE_SHARED_LIBRARY)
diff --git a/Modules/UseEcos.cmake b/Modules/UseEcos.cmake
index 60324b1..83c9b20 100644
--- a/Modules/UseEcos.cmake
+++ b/Modules/UseEcos.cmake
@@ -185,11 +185,11 @@
 # when using nmake makefiles, the custom buildtype suppresses the default cl.exe flags
 # and the rules for creating objects are adjusted for gcc
   set(CMAKE_BUILD_TYPE CUSTOM_ECOS_BUILD)
-  set(CMAKE_C_COMPILE_OBJECT     "<CMAKE_C_COMPILER>   <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
+  set(CMAKE_C_COMPILE_OBJECT     "<CMAKE_C_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
   set(CMAKE_CXX_COMPILE_OBJECT   "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
 # special link commands for ecos-executables
-  set(CMAKE_CXX_LINK_EXECUTABLE  "<CMAKE_CXX_COMPILER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS>  -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib  -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
-  set(CMAKE_C_LINK_EXECUTABLE    "<CMAKE_C_COMPILER>   <CMAKE_C_LINK_FLAGS>   <OBJECTS>  -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib  -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
+  set(CMAKE_CXX_LINK_EXECUTABLE  "<CMAKE_CXX_COMPILER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS> -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
+  set(CMAKE_C_LINK_EXECUTABLE    "<CMAKE_C_COMPILER> <CMAKE_C_LINK_FLAGS> <OBJECTS> -o <TARGET> ${_ecos_EXTRA_LIBS} -nostdlib -nostartfiles -L${CMAKE_CURRENT_BINARY_DIR}/ecos/install/lib -Ttarget.ld ${ECOS_LD_MCPU}")
 # some strict compiler flags
   set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes")
   set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual -fno-rtti -Wctor-dtor-privacy -fno-strict-aliasing -fno-exceptions")
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 467abe9..564e647 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -1,6 +1,11 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
+# To ensure maximum portability across various compilers and platforms
+# deactivate any compiler extensions
+set(CMAKE_C_EXTENSIONS FALSE)
+set(CMAKE_CXX_EXTENSIONS FALSE)
+
 include(CheckIncludeFile)
 # Check if we can build support for ELF parsing.
 if(CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD")
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index f21ea80..61750d3 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 17)
-set(CMake_VERSION_PATCH 20200319)
+set(CMake_VERSION_PATCH 20200330)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
index 509ac65..2806c61 100644
--- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -544,10 +544,7 @@
   if (group->ParentGroup) {
     cmCPackIFWPackage* package = this->GetGroupPackage(group->ParentGroup);
     bool dot = !this->ResolveDuplicateNames;
-    if (dot && name.substr(0, package->Name.size()) == package->Name) {
-      dot = false;
-    }
-    if (dot) {
+    if (dot && !cmHasPrefix(name, package->Name)) {
       name = package->Name + "." + name;
     }
   }
@@ -576,10 +573,7 @@
       return package->Name;
     }
     bool dot = !this->ResolveDuplicateNames;
-    if (dot && name.substr(0, package->Name.size()) == package->Name) {
-      dot = false;
-    }
-    if (dot) {
+    if (dot && !cmHasPrefix(name, package->Name)) {
       name = package->Name + "." + name;
     }
   }
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx
index 9a9cd56..56a74c5 100644
--- a/Source/CPack/IFW/cmCPackIFWPackage.cxx
+++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx
@@ -55,8 +55,7 @@
   if (dashPos != std::string::npos) {
     pos = dashPos;
   }
-  this->Name =
-    pos == std::string::npos ? dependence : dependence.substr(0, pos);
+  this->Name = dependence.substr(0, pos);
 }
 
 std::string cmCPackIFWPackage::DependenceStruct::NameWithCompare() const
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
index 67d3d32..e481d13 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -98,7 +98,7 @@
     command << " -ext " << QuotePath(ext);
   }
 
-  if (sourceFile.rfind(this->CPackTopLevel, 0) != 0) {
+  if (!cmHasSuffix(sourceFile, this->CPackTopLevel)) {
     command << " " << QuotePath("-I" + this->CPackTopLevel);
   }
 
@@ -350,8 +350,7 @@
   std::vector<std::string> options = GetOptions();
 
   for (std::string const& name : options) {
-    if (name.length() > prefix.length() &&
-        name.substr(0, prefix.length()) == prefix) {
+    if (cmHasPrefix(name, prefix)) {
       std::string id = name.substr(prefix.length());
       std::string value = GetOption(name.c_str());
 
@@ -1099,14 +1098,14 @@
   cmCryptoHash sha1(cmCryptoHash::AlgoSHA1);
   std::string const hash = sha1.HashString(path);
 
-  std::string identifier = cmStrCat(cm::string_view(hash).substr(0, 7), '_');
-
   const size_t maxFileNameLength = 52;
+  std::string identifier =
+    cmStrCat(cm::string_view(hash).substr(0, 7), '_',
+             cm::string_view(normalizedFilename).substr(0, maxFileNameLength));
+
+  // if the name was truncated
   if (normalizedFilename.length() > maxFileNameLength) {
-    identifier += normalizedFilename.substr(0, maxFileNameLength - 3);
     identifier += "...";
-  } else {
-    identifier += normalizedFilename;
   }
 
   return identifier;
diff --git a/Source/CPack/WiX/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx
index 3668b46..9685a7f 100644
--- a/Source/CPack/WiX/cmWIXAccessControlList.cxx
+++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx
@@ -2,6 +2,8 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmWIXAccessControlList.h"
 
+#include <cm/string_view>
+
 #include "cmCPackGenerator.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
@@ -35,12 +37,13 @@
     return;
   }
 
-  std::string user_and_domain = entry.substr(0, pos);
-  std::string permission_string = entry.substr(pos + 1);
+  cm::string_view enview(entry);
+  cm::string_view user_and_domain = enview.substr(0, pos);
+  cm::string_view permission_string = enview.substr(pos + 1);
 
   pos = user_and_domain.find('@');
-  std::string user;
-  std::string domain;
+  cm::string_view user;
+  cm::string_view domain;
   if (pos != std::string::npos) {
     user = user_and_domain.substr(0, pos);
     domain = user_and_domain.substr(pos + 1);
@@ -51,9 +54,9 @@
   std::vector<std::string> permissions = cmTokenize(permission_string, ",");
 
   this->SourceWriter.BeginElement("Permission");
-  this->SourceWriter.AddAttribute("User", user);
+  this->SourceWriter.AddAttribute("User", std::string(user));
   if (!domain.empty()) {
-    this->SourceWriter.AddAttribute("Domain", domain);
+    this->SourceWriter.AddAttribute("Domain", std::string(domain));
   }
   for (std::string const& permission : permissions) {
     this->EmitBooleanAttribute(entry, cmTrimWhitespace(permission));
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
index c0d879a..b4085d5 100644
--- a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
@@ -1,5 +1,10 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
+#if defined(__CYGWIN__)
+// For S_IWRITE symbol
+#  define _DEFAULT_SOURCE
+#endif
+
 #include "cmWIXFilesSourceWriter.h"
 
 #include "cm_sys_stat.h"
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
index 363f536..6b30407 100644
--- a/Source/CPack/cmCPackNSISGenerator.cxx
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -68,7 +68,7 @@
 
       // Use the custom component install directory if we have one
       if (pos != std::string::npos) {
-        const std::string componentName = fileN.substr(0, pos);
+        auto componentName = cm::string_view(fileN).substr(0, pos);
         outputDir = CustomComponentInstallDirectory(componentName);
       } else {
         outputDir = CustomComponentInstallDirectory(fileN);
@@ -103,7 +103,7 @@
         componentName = fileN.substr(0, slash);
 
         // Strip off the component part of the path.
-        fileN = fileN.substr(slash + 1);
+        fileN.erase(0, slash + 1);
       }
     }
     std::replace(fileN.begin(), fileN.end(), '/', '\\');
@@ -672,7 +672,7 @@
 
   const std::string componentOutputDir =
     CustomComponentInstallDirectory(component->Name);
-  componentCode += "  SetOutPath \"" + componentOutputDir + "\"\n";
+  componentCode += cmStrCat("  SetOutPath \"", componentOutputDir, "\"\n");
 
   // Create the actual installation commands
   if (component->IsDownloaded) {
@@ -921,12 +921,11 @@
 }
 
 std::string cmCPackNSISGenerator::CustomComponentInstallDirectory(
-  const std::string& componentName)
+  cm::string_view componentName)
 {
-  const char* outputDir =
-    this->GetOption("CPACK_NSIS_" + componentName + "_INSTALL_DIRECTORY");
-  const std::string componentOutputDir = (outputDir ? outputDir : "$INSTDIR");
-  return componentOutputDir;
+  const char* outputDir = this->GetOption(
+    cmStrCat("CPACK_NSIS_", componentName, "_INSTALL_DIRECTORY"));
+  return outputDir ? outputDir : "$INSTDIR";
 }
 
 std::string cmCPackNSISGenerator::TranslateNewlines(std::string str)
diff --git a/Source/CPack/cmCPackNSISGenerator.h b/Source/CPack/cmCPackNSISGenerator.h
index 0af37af..88cba45 100644
--- a/Source/CPack/cmCPackNSISGenerator.h
+++ b/Source/CPack/cmCPackNSISGenerator.h
@@ -10,6 +10,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmCPackGenerator.h"
 
 class cmCPackComponent;
@@ -75,8 +77,7 @@
 
   /// Returns the custom install directory if available for the specified
   /// component, otherwise $INSTDIR is returned.
-  std::string CustomComponentInstallDirectory(
-    const std::string& componentName);
+  std::string CustomComponentInstallDirectory(cm::string_view componentName);
 
   /// Translations any newlines found in the string into \\r\\n, so that the
   /// resulting string can be used within NSIS.
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index dc31623..2e5bde2 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -85,7 +85,7 @@
     return 0;
   }
   std::string key = value.substr(0, pos);
-  value = value.substr(pos + 1);
+  value.erase(0, pos + 1);
   def->Map[key] = value;
   cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG,
               "Set CPack variable: " << key << " to \"" << value << "\""
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index 5e29386..db426b2 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -379,7 +379,7 @@
   const std::vector<std::string>& allArgs)
 {
   // --build-and-test options
-  if (currentArg.find("--build-and-test", 0) == 0 &&
+  if (cmHasLiteralPrefix(currentArg, "--build-and-test") &&
       idx < allArgs.size() - 1) {
     if (idx + 2 < allArgs.size()) {
       idx++;
@@ -397,25 +397,29 @@
       return 0;
     }
   }
-  if (currentArg.find("--build-target", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--build-target") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->BuildTargets.push_back(allArgs[idx]);
   }
-  if (currentArg.find("--build-nocmake", 0) == 0) {
+  if (cmHasLiteralPrefix(currentArg, "--build-nocmake")) {
     this->BuildNoCMake = true;
   }
-  if (currentArg.find("--build-run-dir", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--build-run-dir") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->BuildRunDir = allArgs[idx];
   }
-  if (currentArg.find("--build-two-config", 0) == 0) {
+  if (cmHasLiteralPrefix(currentArg, "--build-two-config")) {
     this->BuildTwoConfig = true;
   }
-  if (currentArg.find("--build-exe-dir", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--build-exe-dir") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->ExecutableDirectory = allArgs[idx];
   }
-  if (currentArg.find("--test-timeout", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--test-timeout") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->Timeout = cmDuration(atof(allArgs[idx].c_str()));
   }
@@ -431,31 +435,33 @@
     idx++;
     this->BuildGeneratorToolset = allArgs[idx];
   }
-  if (currentArg.find("--build-project", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--build-project") &&
+      idx < allArgs.size() - 1) {
     idx++;
     this->BuildProject = allArgs[idx];
   }
-  if (currentArg.find("--build-makeprogram", 0) == 0 &&
+  if (cmHasLiteralPrefix(currentArg, "--build-makeprogram") &&
       idx < allArgs.size() - 1) {
     idx++;
     this->BuildMakeProgram = allArgs[idx];
   }
-  if (currentArg.find("--build-config-sample", 0) == 0 &&
+  if (cmHasLiteralPrefix(currentArg, "--build-config-sample") &&
       idx < allArgs.size() - 1) {
     idx++;
     this->ConfigSample = allArgs[idx];
   }
-  if (currentArg.find("--build-noclean", 0) == 0) {
+  if (cmHasLiteralPrefix(currentArg, "--build-noclean")) {
     this->BuildNoClean = true;
   }
-  if (currentArg.find("--build-options", 0) == 0) {
+  if (cmHasLiteralPrefix(currentArg, "--build-options")) {
     while (idx + 1 < allArgs.size() && allArgs[idx + 1] != "--build-target" &&
            allArgs[idx + 1] != "--test-command") {
       ++idx;
       this->BuildOptions.push_back(allArgs[idx]);
     }
   }
-  if (currentArg.find("--test-command", 0) == 0 && idx < allArgs.size() - 1) {
+  if (cmHasLiteralPrefix(currentArg, "--test-command") &&
+      idx < allArgs.size() - 1) {
     ++idx;
     this->TestCommand = allArgs[idx];
     while (idx + 1 < allArgs.size()) {
diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx
index 03a3fd3..90c5b2a 100644
--- a/Source/CTest/cmCTestBuildHandler.cxx
+++ b/Source/CTest/cmCTestBuildHandler.cxx
@@ -386,24 +386,20 @@
   if (this->CTest->GetCTestConfiguration("SourceDirectory").size() > 20) {
     std::string srcdir =
       this->CTest->GetCTestConfiguration("SourceDirectory") + "/";
-    for (cc = srcdir.size() - 2; cc > 0; cc--) {
-      if (srcdir[cc] == '/') {
-        srcdir = srcdir.substr(0, cc + 1);
-        break;
-      }
+    cc = srcdir.rfind('/', srcdir.size() - 2);
+    if (cc != std::string::npos) {
+      srcdir.resize(cc + 1);
+      this->SimplifySourceDir = std::move(srcdir);
     }
-    this->SimplifySourceDir = srcdir;
   }
   if (this->CTest->GetCTestConfiguration("BuildDirectory").size() > 20) {
     std::string bindir =
       this->CTest->GetCTestConfiguration("BuildDirectory") + "/";
-    for (cc = bindir.size() - 2; cc > 0; cc--) {
-      if (bindir[cc] == '/') {
-        bindir = bindir.substr(0, cc + 1);
-        break;
-      }
+    cc = bindir.rfind('/', bindir.size() - 2);
+    if (cc != std::string::npos) {
+      bindir.resize(cc + 1);
+      this->SimplifyBuildDir = std::move(bindir);
     }
-    this->SimplifyBuildDir = bindir;
   }
 
   // Ok, let's do the build
diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx
index 2c8f119..daa10c9 100644
--- a/Source/CTest/cmCTestCoverageHandler.cxx
+++ b/Source/CTest/cmCTestCoverageHandler.cxx
@@ -680,8 +680,9 @@
 //
 #ifdef _WIN32
 #  define fnc(s) cmSystemTools::LowerCase(s)
+#  define fnc_prefix(s, t) fnc(s.substr(0, t.size())) == fnc(t)
 #else
-#  define fnc(s) s
+#  define fnc_prefix(s, t) cmHasPrefix(s, t)
 #endif
 
 bool IsFileInDir(const std::string& infile, const std::string& indir)
@@ -689,8 +690,8 @@
   std::string file = cmSystemTools::CollapseFullPath(infile);
   std::string dir = cmSystemTools::CollapseFullPath(indir);
 
-  return file.size() > dir.size() &&
-    fnc(file.substr(0, dir.size())) == fnc(dir) && file[dir.size()] == '/';
+  return file.size() > dir.size() && fnc_prefix(file, dir) &&
+    file[dir.size()] == '/';
 }
 
 int cmCTestCoverageHandler::HandlePHPCoverage(
@@ -1709,29 +1710,26 @@
 
         // Read the coverage count from the beginning of the Trace.py output
         // line
-        std::string prefix = nl.substr(0, 6);
-        if (prefix[5] != ' ' && prefix[5] != ':') {
-          // This is a hack. We should really do something more elaborate
-          prefix = nl.substr(0, 7);
-          if (prefix[6] != ' ' && prefix[6] != ':') {
-            prefix = nl.substr(0, 8);
-            if (prefix[7] != ' ' && prefix[7] != ':') {
-              cmCTestLog(this->CTest, ERROR_MESSAGE,
-                         "Currently the limit is maximum coverage of 999999"
-                           << std::endl);
-            }
+        std::string::size_type pos;
+        int cov = 0;
+        // This is a hack. We should really do something more elaborate
+        for (pos = 5; pos < 8; pos++) {
+          if (nl[pos] == ' ') {
+            // This line does not have ':' so no coverage here. That said,
+            // Trace.py does not handle not covered lines versus comments etc.
+            // So, this will be set to 0.
+            break;
+          }
+          if (nl[pos] == ':') {
+            cov = atoi(nl.substr(0, pos - 1).c_str());
+            break;
           }
         }
-        int cov = atoi(prefix.c_str());
-        if (prefix[prefix.size() - 1] != ':') {
-          // This line does not have ':' so no coverage here. That said,
-          // Trace.py does not handle not covered lines versus comments etc.
-          // So, this will be set to 0.
-          cov = 0;
+        if (pos == 8) {
+          cmCTestLog(this->CTest, ERROR_MESSAGE,
+                     "Currently the limit is maximum coverage of 999999"
+                       << std::endl);
         }
-        cmCTestOptionalLog(
-          this->CTest, DEBUG,
-          "Prefix: " << prefix << " cov: " << cov << std::endl, this->Quiet);
         // Read the line number starting at the 10th character of the gcov
         // output line
         long lineIdx = cnt;
diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx
index 3f3c107..568b091 100644
--- a/Source/CTest/cmCTestGIT.cxx
+++ b/Source/CTest/cmCTestGIT.cxx
@@ -6,6 +6,7 @@
 #include <cstdio>
 #include <cstdlib>
 #include <ctime>
+#include <utility>
 #include <vector>
 
 #include "cmsys/FStream.hxx"
@@ -193,7 +194,8 @@
       if (line.find("\tnot-for-merge\t") == std::string::npos) {
         std::string::size_type pos = line.find('\t');
         if (pos != std::string::npos) {
-          sha1 = line.substr(0, pos);
+          sha1 = std::move(line);
+          sha1.resize(pos);
         }
       }
     }
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 5be9332..4fa4dc0 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -284,12 +284,14 @@
   // if the argument has a , in it then it needs to be broken into the fist
   // argument (which is the script) and the second argument which will be
   // passed into the scripts as S_ARG
-  std::string script = total_script_arg;
+  std::string script;
   std::string script_arg;
   const std::string::size_type comma_pos = total_script_arg.find(',');
   if (comma_pos != std::string::npos) {
     script = total_script_arg.substr(0, comma_pos);
     script_arg = total_script_arg.substr(comma_pos + 1);
+  } else {
+    script = total_script_arg;
   }
   // make sure the file exists
   if (!cmSystemTools::FileExists(script)) {
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 22ab48f..811a7e8 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -260,11 +260,10 @@
         cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
         cmake* cm = ch->GetCMake();
         if (cm) {
-          const char* subproject =
-            cm->GetState()->GetGlobalProperty("SubProject");
+          cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
           if (subproject) {
             upload_as += "&subproject=";
-            upload_as += ctest_curl.Escape(subproject);
+            upload_as += ctest_curl.Escape(*subproject);
           }
         }
       }
@@ -506,18 +505,19 @@
   curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT);
   curl.SetHttpHeaders(this->HttpHeaders);
   std::string url = this->CTest->GetSubmitURL();
-  std::string fields;
-  std::string::size_type pos = url.find('?');
-  if (pos != std::string::npos) {
-    fields = url.substr(pos + 1);
-    url = url.substr(0, pos);
-  }
   if (!cmHasLiteralPrefix(url, "http://") &&
       !cmHasLiteralPrefix(url, "https://")) {
     cmCTestLog(this->CTest, ERROR_MESSAGE,
                "Only http and https are supported for CDASH_UPLOAD\n");
     return -1;
   }
+
+  std::string fields;
+  std::string::size_type pos = url.find('?');
+  if (pos != std::string::npos) {
+    fields = url.substr(pos + 1);
+    url.erase(pos);
+  }
   bool internalTest = cmIsOn(this->GetOption("InternalTest"));
 
   // Get RETRY_COUNT and RETRY_DELAY values if they were set.
@@ -555,11 +555,11 @@
   // a "&subproject=subprojectname" to the first POST.
   cmCTestScriptHandler* ch = this->CTest->GetScriptHandler();
   cmake* cm = ch->GetCMake();
-  const char* subproject = cm->GetState()->GetGlobalProperty("SubProject");
+  cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
   // TODO: Encode values for a URL instead of trusting caller.
   std::ostringstream str;
   if (subproject) {
-    str << "subproject=" << curl.Escape(subproject) << "&";
+    str << "subproject=" << curl.Escape(*subproject) << "&";
   }
   auto timeNow =
     std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 8513f4b..1feac3a 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -18,12 +18,14 @@
 #include <utility>
 
 #include <cm/memory>
+#include <cm/string_view>
 
 #include "cmsys/FStream.hxx"
 #include <cmsys/Base64.h>
 #include <cmsys/Directory.hxx>
 #include <cmsys/RegularExpression.hxx>
 
+#include "cm_static_string_view.hxx"
 #include "cm_utf8.h"
 
 #include "cmAlgorithms.h"
@@ -1893,7 +1895,8 @@
         continue;
       }
 
-      int val = atoi(line.substr(0, pos).c_str());
+      line.erase(pos);
+      int val = atoi(line.c_str());
       this->TestsToRun.push_back(val);
     }
     ifs.close();
@@ -2089,11 +2092,11 @@
   }
 }
 
-bool cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
+void cmCTestTestHandler::CleanTestOutput(std::string& output, size_t length)
 {
   if (!length || length >= output.size() ||
       output.find("CTEST_FULL_OUTPUT") != std::string::npos) {
-    return true;
+    return;
   }
 
   // Truncate at given length but do not break in the middle of a multi-byte
@@ -2114,7 +2117,7 @@
       ++current;
     }
   }
-  output = output.substr(0, current - begin);
+  output.erase(current - begin);
 
   // Append truncation message.
   std::ostringstream msg;
@@ -2124,7 +2127,6 @@
          "of "
       << length << " bytes.\n";
   output += msg.str();
-  return true;
 }
 
 bool cmCTestTestHandler::SetTestsProperties(
@@ -2145,16 +2147,16 @@
   }
   ++it; // skip PROPERTIES
   for (; it != args.end(); ++it) {
-    std::string key = *it;
+    std::string const& key = *it;
     ++it;
     if (it == args.end()) {
       break;
     }
-    std::string val = *it;
+    std::string const& val = *it;
     for (std::string const& t : tests) {
       for (cmCTestTestProperties& rt : this->TestList) {
         if (t == rt.Name) {
-          if (key == "_BACKTRACE_TRIPLES") {
+          if (key == "_BACKTRACE_TRIPLES"_s) {
             std::vector<std::string> triples;
             // allow empty args in the triples
             cmExpandList(val, triples, true);
@@ -2178,91 +2180,70 @@
                 rt.Backtrace = rt.Backtrace.Push(fc);
               }
             }
-          }
-          if (key == "WILL_FAIL") {
+          } else if (key == "WILL_FAIL"_s) {
             rt.WillFail = cmIsOn(val);
-          }
-          if (key == "DISABLED") {
+          } else if (key == "DISABLED"_s) {
             rt.Disabled = cmIsOn(val);
-          }
-          if (key == "ATTACHED_FILES") {
+          } else if (key == "ATTACHED_FILES"_s) {
             cmExpandList(val, rt.AttachedFiles);
-          }
-          if (key == "ATTACHED_FILES_ON_FAIL") {
+          } else if (key == "ATTACHED_FILES_ON_FAIL"_s) {
             cmExpandList(val, rt.AttachOnFail);
-          }
-          if (key == "RESOURCE_LOCK") {
+          } else if (key == "RESOURCE_LOCK"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
 
             rt.LockedResources.insert(lval.begin(), lval.end());
-          }
-          if (key == "FIXTURES_SETUP") {
+          } else if (key == "FIXTURES_SETUP"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
 
             rt.FixturesSetup.insert(lval.begin(), lval.end());
-          }
-          if (key == "FIXTURES_CLEANUP") {
+          } else if (key == "FIXTURES_CLEANUP"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
 
             rt.FixturesCleanup.insert(lval.begin(), lval.end());
-          }
-          if (key == "FIXTURES_REQUIRED") {
+          } else if (key == "FIXTURES_REQUIRED"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
 
             rt.FixturesRequired.insert(lval.begin(), lval.end());
-          }
-          if (key == "TIMEOUT") {
+          } else if (key == "TIMEOUT"_s) {
             rt.Timeout = cmDuration(atof(val.c_str()));
             rt.ExplicitTimeout = true;
-          }
-          if (key == "COST") {
+          } else if (key == "COST"_s) {
             rt.Cost = static_cast<float>(atof(val.c_str()));
-          }
-          if (key == "REQUIRED_FILES") {
+          } else if (key == "REQUIRED_FILES"_s) {
             cmExpandList(val, rt.RequiredFiles);
-          }
-          if (key == "RUN_SERIAL") {
+          } else if (key == "RUN_SERIAL"_s) {
             rt.RunSerial = cmIsOn(val);
-          }
-          if (key == "FAIL_REGULAR_EXPRESSION") {
+          } else if (key == "FAIL_REGULAR_EXPRESSION"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
             for (std::string const& cr : lval) {
               rt.ErrorRegularExpressions.emplace_back(cr, cr);
             }
-          }
-          if (key == "SKIP_REGULAR_EXPRESSION") {
+          } else if (key == "SKIP_REGULAR_EXPRESSION"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
             for (std::string const& cr : lval) {
               rt.SkipRegularExpressions.emplace_back(cr, cr);
             }
-          }
-          if (key == "PROCESSORS") {
+          } else if (key == "PROCESSORS"_s) {
             rt.Processors = atoi(val.c_str());
             if (rt.Processors < 1) {
               rt.Processors = 1;
             }
-          }
-          if (key == "PROCESSOR_AFFINITY") {
+          } else if (key == "PROCESSOR_AFFINITY"_s) {
             rt.WantAffinity = cmIsOn(val);
-          }
-          if (key == "RESOURCE_GROUPS") {
+          } else if (key == "RESOURCE_GROUPS"_s) {
             if (!ParseResourceGroupsProperty(val, rt.ResourceGroups)) {
               return false;
             }
-          }
-          if (key == "SKIP_RETURN_CODE") {
+          } else if (key == "SKIP_RETURN_CODE"_s) {
             rt.SkipReturnCode = atoi(val.c_str());
             if (rt.SkipReturnCode < 0 || rt.SkipReturnCode > 255) {
               rt.SkipReturnCode = -1;
             }
-          }
-          if (key == "DEPENDS") {
+          } else if (key == "DEPENDS"_s) {
             cmExpandList(val, rt.Depends);
-          }
-          if (key == "ENVIRONMENT") {
+          } else if (key == "ENVIRONMENT"_s) {
             cmExpandList(val, rt.Environment);
-          }
-          if (key == "LABELS") {
+          } else if (key == "LABELS"_s) {
             std::vector<std::string> Labels = cmExpandedList(val);
             rt.Labels.insert(rt.Labels.end(), Labels.begin(), Labels.end());
             // sort the array
@@ -2270,8 +2251,7 @@
             // remove duplicates
             auto new_end = std::unique(rt.Labels.begin(), rt.Labels.end());
             rt.Labels.erase(new_end, rt.Labels.end());
-          }
-          if (key == "MEASUREMENT") {
+          } else if (key == "MEASUREMENT"_s) {
             size_t pos = val.find_first_of('=');
             if (pos != std::string::npos) {
               std::string mKey = val.substr(0, pos);
@@ -2280,17 +2260,14 @@
             } else {
               rt.Measurements[val] = "1";
             }
-          }
-          if (key == "PASS_REGULAR_EXPRESSION") {
+          } else if (key == "PASS_REGULAR_EXPRESSION"_s) {
             std::vector<std::string> lval = cmExpandedList(val);
             for (std::string const& cr : lval) {
               rt.RequiredRegularExpressions.emplace_back(cr, cr);
             }
-          }
-          if (key == "WORKING_DIRECTORY") {
+          } else if (key == "WORKING_DIRECTORY"_s) {
             rt.Directory = val;
-          }
-          if (key == "TIMEOUT_AFTER_MATCH") {
+          } else if (key == "TIMEOUT_AFTER_MATCH"_s) {
             std::vector<std::string> propArgs = cmExpandedList(val);
             if (propArgs.size() != 2) {
               cmCTestLog(this->CTest, WARNING,
@@ -2330,16 +2307,16 @@
   }
   ++it; // skip PROPERTIES
   for (; it != args.end(); ++it) {
-    std::string key = *it;
+    std::string const& key = *it;
     ++it;
     if (it == args.end()) {
       break;
     }
-    std::string val = *it;
+    std::string const& val = *it;
     for (cmCTestTestProperties& rt : this->TestList) {
       std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
       if (cwd == rt.Directory) {
-        if (key == "LABELS") {
+        if (key == "LABELS"_s) {
           std::vector<std::string> DirectoryLabels = cmExpandedList(val);
           rt.Labels.insert(rt.Labels.end(), DirectoryLabels.begin(),
                            DirectoryLabels.end());
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index b1c8755..8a49ec2 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -235,7 +235,7 @@
   void AttachFiles(cmXMLWriter& xml, cmCTestTestResult& result);
 
   //! Clean test output to specified length
-  bool CleanTestOutput(std::string& output, size_t length);
+  void CleanTestOutput(std::string& output, size_t length);
 
   cmDuration ElapsedTestingTime;
 
diff --git a/Source/CTest/cmParseCacheCoverage.cxx b/Source/CTest/cmParseCacheCoverage.cxx
index 8c4da75..1a5e7c5 100644
--- a/Source/CTest/cmParseCacheCoverage.cxx
+++ b/Source/CTest/cmParseCacheCoverage.cxx
@@ -19,7 +19,7 @@
 {
 }
 
-bool cmParseCacheCoverage::LoadCoverageData(const char* d)
+bool cmParseCacheCoverage::LoadCoverageData(std::string const& d)
 {
   // load all the .mcov files in the specified directory
   cmsys::Directory dir;
@@ -155,7 +155,7 @@
     // if we have a routine name, check for end of routine
     else {
       // Totals in arg 0 marks the end of a routine
-      if (separateLine[0].substr(0, 6) == "Totals") {
+      if (cmHasLiteralPrefix(separateLine[0], "Totals")) {
         routine.clear(); // at the end of this routine
         filepath.clear();
         continue; // move to next line
diff --git a/Source/CTest/cmParseCacheCoverage.h b/Source/CTest/cmParseCacheCoverage.h
index e89b9e4..3b554f3 100644
--- a/Source/CTest/cmParseCacheCoverage.h
+++ b/Source/CTest/cmParseCacheCoverage.h
@@ -26,7 +26,7 @@
 
 protected:
   // implement virtual from parent
-  bool LoadCoverageData(const char* dir) override;
+  bool LoadCoverageData(std::string const& dir) override;
   // remove files with no coverage
   void RemoveUnCoveredFiles();
   // Read a single mcov file
diff --git a/Source/CTest/cmParseCoberturaCoverage.cxx b/Source/CTest/cmParseCoberturaCoverage.cxx
index 05da84e..711a856 100644
--- a/Source/CTest/cmParseCoberturaCoverage.cxx
+++ b/Source/CTest/cmParseCoberturaCoverage.cxx
@@ -67,7 +67,7 @@
           // Check if this is an absolute path that falls within our
           // source or binary directories.
           for (std::string const& filePath : FilePaths) {
-            if (filename.find(filePath) == 0) {
+            if (cmHasPrefix(filename, filePath)) {
               this->CurFileName = filename;
               break;
             }
diff --git a/Source/CTest/cmParseGTMCoverage.cxx b/Source/CTest/cmParseGTMCoverage.cxx
index 1dc5b70..14417cc 100644
--- a/Source/CTest/cmParseGTMCoverage.cxx
+++ b/Source/CTest/cmParseGTMCoverage.cxx
@@ -19,7 +19,7 @@
 {
 }
 
-bool cmParseGTMCoverage::LoadCoverageData(const char* d)
+bool cmParseGTMCoverage::LoadCoverageData(std::string const& d)
 {
   // load all the .mcov files in the specified directory
   cmsys::Directory dir;
diff --git a/Source/CTest/cmParseGTMCoverage.h b/Source/CTest/cmParseGTMCoverage.h
index fe0ae0b..41cc7f5 100644
--- a/Source/CTest/cmParseGTMCoverage.h
+++ b/Source/CTest/cmParseGTMCoverage.h
@@ -25,7 +25,7 @@
 
 protected:
   // implement virtual from parent
-  bool LoadCoverageData(const char* dir) override;
+  bool LoadCoverageData(std::string const& dir) override;
   // Read a single mcov file
   bool ReadMCovFile(const char* f);
   // find out what line in a mumps file (filepath) the given entry point
diff --git a/Source/CTest/cmParseMumpsCoverage.cxx b/Source/CTest/cmParseMumpsCoverage.cxx
index b16f101..dc3064d 100644
--- a/Source/CTest/cmParseMumpsCoverage.cxx
+++ b/Source/CTest/cmParseMumpsCoverage.cxx
@@ -39,9 +39,9 @@
       std::string type = line.substr(0, pos);
       std::string path = line.substr(pos + 1);
       if (type == "packages") {
-        this->LoadPackages(path.c_str());
+        this->LoadPackages(path);
       } else if (type == "coverage_dir") {
-        this->LoadCoverageData(path.c_str());
+        this->LoadCoverageData(path);
       } else {
         cmCTestLog(this->CTest, ERROR_MESSAGE,
                    "Parse Error in Mumps coverage file :\n"
@@ -105,7 +105,7 @@
   }
 }
 
-bool cmParseMumpsCoverage::LoadPackages(const char* d)
+bool cmParseMumpsCoverage::LoadPackages(std::string const& d)
 {
   cmsys::Glob glob;
   glob.RecurseOn();
@@ -113,7 +113,8 @@
   glob.FindFiles(pat);
   for (std::string& file : glob.GetFiles()) {
     std::string name = cmSystemTools::GetFilenameName(file);
-    this->RoutineToDirectory[name.substr(0, name.size() - 2)] = file;
+    name.erase(name.size() - 2);
+    this->RoutineToDirectory[name] = file;
     // initialize each file, this is left out until CDash is fixed
     // to handle large numbers of files
     this->InitializeMumpsFile(file);
diff --git a/Source/CTest/cmParseMumpsCoverage.h b/Source/CTest/cmParseMumpsCoverage.h
index 2c54495..8c08702 100644
--- a/Source/CTest/cmParseMumpsCoverage.h
+++ b/Source/CTest/cmParseMumpsCoverage.h
@@ -29,10 +29,10 @@
 protected:
   // sub classes will use this to
   // load all coverage files found in the given directory
-  virtual bool LoadCoverageData(const char* d) = 0;
+  virtual bool LoadCoverageData(std::string const& d) = 0;
   // search the package directory for mumps files and fill
   // in the RoutineToDirectory map
-  bool LoadPackages(const char* dir);
+  bool LoadPackages(std::string const& dir);
   // initialize the coverage information for a single mumps file
   void InitializeMumpsFile(std::string& file);
   // Find mumps file for routine
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 76ffb20..2742fd7 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -249,7 +249,7 @@
   this->PipeReader.reset();
   if (this->ProcessHandleClosed) {
     uv_timer_stop(this->Timer);
-    this->Runner->FinalizeTest();
+    this->Finish();
   }
 }
 
@@ -291,7 +291,7 @@
     // Our on-exit handler already ran but did not finish the test
     // because we were still reading output.  We've just dropped
     // our read handler, so we need to finish the test now.
-    this->Runner->FinalizeTest();
+    this->Finish();
   }
 }
 
@@ -321,6 +321,16 @@
   // Record exit information.
   this->ExitValue = exit_status;
   this->Signal = term_signal;
+
+  this->ProcessHandleClosed = true;
+  if (this->ReadHandleClosed) {
+    uv_timer_stop(this->Timer);
+    this->Finish();
+  }
+}
+
+void cmProcess::Finish()
+{
   this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
   // Because of a processor clock scew the runtime may become slightly
   // negative. If someone changed the system clock while the process was
@@ -329,12 +339,7 @@
   if (this->TotalTime <= cmDuration::zero()) {
     this->TotalTime = cmDuration::zero();
   }
-
-  this->ProcessHandleClosed = true;
-  if (this->ReadHandleClosed) {
-    uv_timer_stop(this->Timer);
-    this->Runner->FinalizeTest();
-  }
+  this->Runner->FinalizeTest();
 }
 
 cmProcess::State cmProcess::GetProcessStatus()
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index 0f69f68..526c920 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -108,6 +108,7 @@
   void OnAllocate(size_t suggested_size, uv_buf_t* buf);
 
   void StartTimer();
+  void Finish();
 
   class Buffer : public std::vector<char>
   {
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index 01fce85..9a26db5 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -16,6 +16,7 @@
 #include "cmDocumentation.h"
 #include "cmDocumentationEntry.h" // IWYU pragma: keep
 #include "cmState.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmake.h"
 
@@ -111,8 +112,8 @@
 
   std::string cacheDir = cmSystemTools::GetCurrentWorkingDirectory();
   for (i = 1; i < args.size(); ++i) {
-    std::string arg = args[i];
-    if (arg.find("-B", 0) == 0) {
+    std::string const& arg = args[i];
+    if (cmHasPrefix(arg, "-B")) {
       cacheDir = arg.substr(2);
     }
   }
diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
index 9a0d966..9250fbc 100644
--- a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
+++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx
@@ -71,11 +71,11 @@
       break;
     }
     case cmStateEnums::STRING: {
-      const char* stringsProp = state->GetCacheEntryProperty(key, "STRINGS");
+      cmProp stringsProp = state->GetCacheEntryProperty(key, "STRINGS");
       if (stringsProp) {
         auto ow =
           cm::make_unique<cmCursesOptionsWidget>(this->EntryWidth, 1, 1, 1);
-        for (std::string const& opt : cmExpandedList(stringsProp)) {
+        for (std::string const& opt : cmExpandedList(*stringsProp)) {
           ow->AddOption(opt);
         }
         ow->SetOption(*value);
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 9670595..7752a68 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -407,9 +407,10 @@
     auto cmakeState = this->CMakeInstance->GetState();
     cmProp existingValue = cmakeState->GetCacheEntryValue(labelValue);
     if (existingValue) {
-      auto help = cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING");
+      cmProp help =
+        cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING");
       if (help) {
-        bar += help;
+        bar += *help;
       }
     }
   }
@@ -802,7 +803,7 @@
         cmCursesWidget* lbl = reinterpret_cast<cmCursesWidget*>(
           field_userptr(this->Fields[findex - 2]));
         const char* curField = lbl->GetValue();
-        const char* helpString = nullptr;
+        cmProp helpString = nullptr;
 
         cmProp existingValue =
           this->CMakeInstance->GetState()->GetCacheEntryValue(curField);
@@ -813,7 +814,7 @@
         if (helpString) {
           this->HelpMessage[1] =
             cmStrCat("Current option is: ", curField, '\n',
-                     "Help string for this option is: ", helpString, '\n');
+                     "Help string for this option is: ", *helpString, '\n');
         } else {
           this->HelpMessage[1] = "";
         }
diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx
index ee81a7d..9d928b2 100644
--- a/Source/QtDialog/CMakeSetup.cxx
+++ b/Source/QtDialog/CMakeSetup.cxx
@@ -201,8 +201,7 @@
         cmSystemTools::CollapseFullPath(args[1].toLocal8Bit().data());
 
       // check if argument is a directory containing CMakeCache.txt
-      std::string buildFilePath =
-        cmSystemTools::CollapseFullPath("CMakeCache.txt", filePath.c_str());
+      std::string buildFilePath = cmStrCat(filePath, "/CMakeCache.txt");
 
       // check if argument is a CMakeCache.txt file
       if (cmSystemTools::GetFilenameName(filePath) == "CMakeCache.txt" &&
@@ -211,8 +210,7 @@
       }
 
       // check if argument is a directory containing CMakeLists.txt
-      std::string srcFilePath =
-        cmSystemTools::CollapseFullPath("CMakeLists.txt", filePath.c_str());
+      std::string srcFilePath = cmStrCat(filePath, "/CMakeLists.txt");
 
       if (cmSystemTools::FileExists(buildFilePath.c_str())) {
         dialog.setBinaryDirectory(QString::fromLocal8Bit(
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx
index eaf50f2..776af81 100644
--- a/Source/QtDialog/QCMake.cxx
+++ b/Source/QtDialog/QCMake.cxx
@@ -306,8 +306,9 @@
 
     QCMakeProperty prop;
     prop.Key = QString::fromLocal8Bit(key.c_str());
-    prop.Help =
-      QString::fromLocal8Bit(state->GetCacheEntryProperty(key, "HELPSTRING"));
+    if (cmProp hs = state->GetCacheEntryProperty(key, "HELPSTRING")) {
+      prop.Help = QString::fromLocal8Bit(hs->c_str());
+    }
     prop.Value = QString::fromLocal8Bit(cachedValue->c_str());
     prop.Advanced = state->GetCacheEntryPropertyAsBool(key, "ADVANCED");
     if (t == cmStateEnums::BOOL) {
@@ -319,10 +320,10 @@
       prop.Type = QCMakeProperty::FILEPATH;
     } else if (t == cmStateEnums::STRING) {
       prop.Type = QCMakeProperty::STRING;
-      const char* stringsProperty =
-        state->GetCacheEntryProperty(key, "STRINGS");
+      cmProp stringsProperty = state->GetCacheEntryProperty(key, "STRINGS");
       if (stringsProperty) {
-        prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";");
+        prop.Strings =
+          QString::fromLocal8Bit(stringsProperty->c_str()).split(";");
       }
     }
 
@@ -484,7 +485,7 @@
 
 void QCMake::checkOpenPossible()
 {
-  auto data = this->BinaryDirectory.toLocal8Bit().data();
+  std::string data = this->BinaryDirectory.toLocal8Bit().data();
   auto possible = this->CMakeInstance->Open(data, true);
   emit openPossible(possible);
 }
diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx
index 0b2750d..fdfd4c0 100644
--- a/Source/bindexplib.cxx
+++ b/Source/bindexplib.cxx
@@ -352,14 +352,14 @@
               line.c_str());
       return false;
     }
-    const std::string sym = line.substr(0, sym_end);
     const char sym_type = line[sym_end + 1];
+    line.resize(sym_end);
     switch (sym_type) {
       case 'D':
-        dataSymbols.insert(sym);
+        dataSymbols.insert(line);
         break;
       case 'T':
-        symbols.insert(sym);
+        symbols.insert(line);
         break;
     }
   }
diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx
index 35eabaf..83d6306 100644
--- a/Source/cmAddSubDirectoryCommand.cxx
+++ b/Source/cmAddSubDirectoryCommand.cxx
@@ -4,6 +4,8 @@
 
 #include <cstring>
 
+#include <cm/string_view>
+
 #include "cmExecutionStatus.h"
 #include "cmMakefile.h"
 #include "cmRange.h"
@@ -86,7 +88,8 @@
     if (binLen > 0 && bin.back() == '/') {
       --binLen;
     }
-    binPath = bin.substr(0, binLen) + srcPath.substr(srcLen);
+    binPath = cmStrCat(cm::string_view(bin).substr(0, binLen),
+                       cm::string_view(srcPath).substr(srcLen));
   } else {
     // Use the binary directory specified.
     // Interpret a relative path with respect to the current binary directory.
diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx
index 289bb72..d6f7500e 100644
--- a/Source/cmAuxSourceDirectoryCommand.cxx
+++ b/Source/cmAuxSourceDirectoryCommand.cxx
@@ -6,6 +6,8 @@
 #include <cstddef>
 #include <utility>
 
+#include <cm/string_view>
+
 #include "cmsys/Directory.hxx"
 
 #include "cmExecutionStatus.h"
@@ -50,11 +52,10 @@
       // Split the filename into base and extension
       std::string::size_type dotpos = file.rfind('.');
       if (dotpos != std::string::npos) {
-        std::string ext = file.substr(dotpos + 1);
-        std::string base = file.substr(0, dotpos);
+        auto ext = cm::string_view(file).substr(dotpos + 1);
         // Process only source files
         auto cm = mf.GetCMakeInstance();
-        if (!base.empty() && cm->IsSourceExtension(ext)) {
+        if (dotpos > 0 && cm->IsSourceExtension(ext)) {
           std::string fullname = cmStrCat(templateDirectory, '/', file);
           // add the file as a class file so
           // depends can be done
diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx
index 0dea825..9ce403d 100644
--- a/Source/cmBinUtilsLinuxELFLinker.cxx
+++ b/Source/cmBinUtilsLinuxELFLinker.cxx
@@ -6,6 +6,7 @@
 #include <sstream>
 
 #include <cm/memory>
+#include <cm/string_view>
 
 #include <cmsys/RegularExpression.hxx>
 
@@ -26,14 +27,16 @@
 
   cmsys::RegularExpressionMatch match;
   if (originRegex.find(rpath.c_str(), match)) {
-    std::string begin = rpath.substr(0, match.start(1));
-    std::string end = rpath.substr(match.end(1));
-    return begin + origin + end;
+    cm::string_view pathv(rpath);
+    auto begin = pathv.substr(0, match.start(1));
+    auto end = pathv.substr(match.end(1));
+    return cmStrCat(begin, origin, end);
   }
   if (originCurlyRegex.find(rpath.c_str(), match)) {
-    std::string begin = rpath.substr(0, match.start());
-    std::string end = rpath.substr(match.end());
-    return begin + origin + end;
+    cm::string_view pathv(rpath);
+    auto begin = pathv.substr(0, match.start());
+    auto end = pathv.substr(match.end());
+    return cmStrCat(begin, origin, end);
   }
   return rpath;
 }
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index fb100b1..c5505f9 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -17,6 +17,7 @@
 #include <vector>
 
 #include <cm/memory>
+#include <cm/string_view>
 #include <cmext/algorithm>
 
 #include "cmsys/Base64.h"
@@ -35,6 +36,8 @@
 #  include <unistd.h> // IWYU pragma: keep
 #endif
 
+#include "cm_static_string_view.hxx"
+
 #include "cmCTestBuildAndTestHandler.h"
 #include "cmCTestBuildHandler.h"
 #include "cmCTestConfigureHandler.h"
@@ -271,9 +274,10 @@
   return this->Impl->TomorrowTag;
 }
 
-std::string cmCTest::CleanString(const std::string& str)
+std::string cmCTest::CleanString(const std::string& str,
+                                 std::string::size_type spos)
 {
-  std::string::size_type spos = str.find_first_not_of(" \n\t\r\f\v");
+  spos = str.find_first_not_of(" \n\t\r\f\v", spos);
   std::string::size_type epos = str.find_last_not_of(" \n\t\r\f\v");
   if (spos == std::string::npos) {
     return std::string();
@@ -724,7 +728,7 @@
         continue;
       }
       while (fin && (line.back() == '\\')) {
-        line = line.substr(0, line.size() - 1);
+        line.resize(line.size() - 1);
         buffer[0] = 0;
         fin.getline(buffer, 1023);
         buffer[1023] = 0;
@@ -738,7 +742,7 @@
         continue;
       }
       std::string key = line.substr(0, cpos);
-      std::string value = cmCTest::CleanString(line.substr(cpos + 1));
+      std::string value = cmCTest::CleanString(line, cpos + 1);
       this->Impl->CTestConfiguration[key] = value;
     }
     fin.close();
@@ -1439,16 +1443,15 @@
     return;
   }
   // This code should go when cdash is changed to use labels only
-  const char* subproject = cm->GetState()->GetGlobalProperty("SubProject");
+  cmProp subproject = cm->GetState()->GetGlobalProperty("SubProject");
   if (subproject) {
     xml.StartElement("Subproject");
-    xml.Attribute("name", subproject);
-    const char* labels =
+    xml.Attribute("name", *subproject);
+    cmProp labels =
       ch->GetCMake()->GetState()->GetGlobalProperty("SubProjectLabels");
     if (labels) {
       xml.StartElement("Labels");
-      std::string l = labels;
-      std::vector<std::string> args = cmExpandedList(l);
+      std::vector<std::string> args = cmExpandedList(*labels);
       for (std::string const& i : args) {
         xml.Element("Label", i);
       }
@@ -1458,10 +1461,10 @@
   }
 
   // This code should stay when cdash only does label based sub-projects
-  const char* label = cm->GetState()->GetGlobalProperty("Label");
+  cmProp label = cm->GetState()->GetGlobalProperty("Label");
   if (label) {
     xml.StartElement("Labels");
-    xml.Element("Label", label);
+    xml.Element("Label", *label);
     xml.EndElement();
   }
 }
@@ -1813,10 +1816,10 @@
       << "  ctest -D NightlyMemoryCheck" << std::endl);
 }
 
-bool cmCTest::CheckArgument(const std::string& arg, const char* varg1,
+bool cmCTest::CheckArgument(const std::string& arg, cm::string_view varg1,
                             const char* varg2)
 {
-  return (varg1 && arg == varg1) || (varg2 && arg == varg2);
+  return (arg == varg1) || (varg2 && arg == varg2);
 }
 
 // Processes one command line argument (and its arguments if any)
@@ -1826,21 +1829,21 @@
                                          std::string& errormsg)
 {
   std::string arg = args[i];
-  if (this->CheckArgument(arg, "-F")) {
+  if (this->CheckArgument(arg, "-F"_s)) {
     this->Impl->Failover = true;
-  }
-  if (this->CheckArgument(arg, "-j", "--parallel") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-j"_s, "--parallel") &&
+             i < args.size() - 1) {
     i++;
     int plevel = atoi(args[i].c_str());
     this->SetParallelLevel(plevel);
     this->Impl->ParallelLevelSetInCli = true;
-  } else if (arg.find("-j") == 0) {
+  } else if (cmHasPrefix(arg, "-j")) {
     int plevel = atoi(arg.substr(2).c_str());
     this->SetParallelLevel(plevel);
     this->Impl->ParallelLevelSetInCli = true;
   }
 
-  if (this->CheckArgument(arg, "--repeat-until-fail")) {
+  else if (this->CheckArgument(arg, "--repeat-until-fail"_s)) {
     if (i >= args.size() - 1) {
       errormsg = "'--repeat-until-fail' requires an argument";
       return false;
@@ -1852,8 +1855,8 @@
     i++;
     long repeat = 1;
     if (!cmStrToLong(args[i], &repeat)) {
-      errormsg =
-        "'--repeat-until-fail' given non-integer value '" + args[i] + "'";
+      errormsg = cmStrCat("'--repeat-until-fail' given non-integer value '",
+                          args[i], "'");
       return false;
     }
     this->Impl->RepeatCount = static_cast<int>(repeat);
@@ -1862,7 +1865,7 @@
     }
   }
 
-  if (this->CheckArgument(arg, "--repeat")) {
+  else if (this->CheckArgument(arg, "--repeat"_s)) {
     if (i >= args.size() - 1) {
       errormsg = "'--repeat' requires an argument";
       return false;
@@ -1890,12 +1893,12 @@
         }
       }
     } else {
-      errormsg = "'--repeat' given invalid value '" + args[i] + "'";
+      errormsg = cmStrCat("'--repeat' given invalid value '", args[i], "'");
       return false;
     }
   }
 
-  if (this->CheckArgument(arg, "--test-load") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--test-load"_s) && i < args.size() - 1) {
     i++;
     unsigned long load;
     if (cmStrToULong(args[i], &load)) {
@@ -1906,76 +1909,66 @@
     }
   }
 
-  if (this->CheckArgument(arg, "--no-compress-output")) {
+  else if (this->CheckArgument(arg, "--no-compress-output"_s)) {
     this->Impl->CompressTestOutput = false;
   }
 
-  if (this->CheckArgument(arg, "--print-labels")) {
+  else if (this->CheckArgument(arg, "--print-labels"_s)) {
     this->Impl->PrintLabels = true;
   }
 
-  if (this->CheckArgument(arg, "--http1.0")) {
+  else if (this->CheckArgument(arg, "--http1.0"_s)) {
     this->Impl->UseHTTP10 = true;
   }
 
-  if (this->CheckArgument(arg, "--timeout") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--timeout"_s) && i < args.size() - 1) {
     i++;
     auto timeout = cmDuration(atof(args[i].c_str()));
     this->Impl->GlobalTimeout = timeout;
   }
 
-  if (this->CheckArgument(arg, "--stop-time") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--stop-time"_s) && i < args.size() - 1) {
     i++;
     this->SetStopTime(args[i]);
   }
 
-  if (this->CheckArgument(arg, "-C", "--build-config") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-C"_s, "--build-config") &&
+           i < args.size() - 1) {
     i++;
     this->SetConfigType(args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "--debug")) {
+  else if (this->CheckArgument(arg, "--debug"_s)) {
     this->Impl->Debug = true;
     this->Impl->ShowLineNumbers = true;
-  }
-  if (this->CheckArgument(arg, "--group") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--group"_s) && i < args.size() - 1) {
     i++;
     this->Impl->SpecificGroup = args[i];
   }
   // This is an undocumented / deprecated option.
   // "Track" has been renamed to "Group".
-  if (this->CheckArgument(arg, "--track") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--track"_s) && i < args.size() - 1) {
     i++;
     this->Impl->SpecificGroup = args[i];
-  }
-  if (this->CheckArgument(arg, "--show-line-numbers")) {
+  } else if (this->CheckArgument(arg, "--show-line-numbers"_s)) {
     this->Impl->ShowLineNumbers = true;
-  }
-  if (this->CheckArgument(arg, "--no-label-summary")) {
+  } else if (this->CheckArgument(arg, "--no-label-summary"_s)) {
     this->Impl->LabelSummary = false;
-  }
-  if (this->CheckArgument(arg, "--no-subproject-summary")) {
+  } else if (this->CheckArgument(arg, "--no-subproject-summary"_s)) {
     this->Impl->SubprojectSummary = false;
-  }
-  if (this->CheckArgument(arg, "-Q", "--quiet")) {
+  } else if (this->CheckArgument(arg, "-Q"_s, "--quiet")) {
     this->Impl->Quiet = true;
-  }
-  if (this->CheckArgument(arg, "--progress")) {
+  } else if (this->CheckArgument(arg, "--progress"_s)) {
     this->Impl->TestProgressOutput = true;
-  }
-  if (this->CheckArgument(arg, "-V", "--verbose")) {
+  } else if (this->CheckArgument(arg, "-V"_s, "--verbose")) {
     this->Impl->Verbose = true;
-  }
-  if (this->CheckArgument(arg, "-VV", "--extra-verbose")) {
+  } else if (this->CheckArgument(arg, "-VV"_s, "--extra-verbose")) {
     this->Impl->ExtraVerbose = true;
     this->Impl->Verbose = true;
-  }
-  if (this->CheckArgument(arg, "--output-on-failure")) {
+  } else if (this->CheckArgument(arg, "--output-on-failure"_s)) {
     this->Impl->OutputTestOutputOnTestFailure = true;
-  }
-  if (this->CheckArgument(arg, "--test-output-size-passed") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--test-output-size-passed"_s) &&
+             i < args.size() - 1) {
     i++;
     long outputSize;
     if (cmStrToLong(args[i], &outputSize)) {
@@ -1985,9 +1978,8 @@
                  "Invalid value for '--test-output-size-passed': " << args[i]
                                                                    << "\n");
     }
-  }
-  if (this->CheckArgument(arg, "--test-output-size-failed") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--test-output-size-failed"_s) &&
+             i < args.size() - 1) {
     i++;
     long outputSize;
     if (cmStrToLong(args[i], &outputSize)) {
@@ -1997,11 +1989,9 @@
                  "Invalid value for '--test-output-size-failed': " << args[i]
                                                                    << "\n");
     }
-  }
-  if (this->CheckArgument(arg, "-N", "--show-only")) {
+  } else if (this->CheckArgument(arg, "-N"_s, "--show-only")) {
     this->Impl->ShowOnly = true;
-  }
-  if (cmHasLiteralPrefix(arg, "--show-only=")) {
+  } else if (cmHasLiteralPrefix(arg, "--show-only=")) {
     this->Impl->ShowOnly = true;
 
     // Check if a specific format is requested. Defaults to human readable
@@ -2019,27 +2009,26 @@
     }
   }
 
-  if (this->CheckArgument(arg, "-O", "--output-log") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-O"_s, "--output-log") &&
+           i < args.size() - 1) {
     i++;
     this->SetOutputLogFileName(args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "--tomorrow-tag")) {
+  else if (this->CheckArgument(arg, "--tomorrow-tag"_s)) {
     this->Impl->TomorrowTag = true;
-  }
-  if (this->CheckArgument(arg, "--force-new-ctest-process")) {
+  } else if (this->CheckArgument(arg, "--force-new-ctest-process"_s)) {
     this->Impl->ForceNewCTestProcess = true;
-  }
-  if (this->CheckArgument(arg, "-W", "--max-width") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-W"_s, "--max-width") &&
+             i < args.size() - 1) {
     i++;
     this->Impl->MaxTestNameWidth = atoi(args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "--interactive-debug-mode") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--interactive-debug-mode"_s) &&
+             i < args.size() - 1) {
     i++;
     this->Impl->InteractiveDebugMode = cmIsOn(args[i]);
-  }
-  if (this->CheckArgument(arg, "--submit-index") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "--submit-index"_s) &&
+             i < args.size() - 1) {
     i++;
     this->Impl->SubmitIndex = atoi(args[i].c_str());
     if (this->Impl->SubmitIndex < 0) {
@@ -2047,24 +2036,27 @@
     }
   }
 
-  if (this->CheckArgument(arg, "--overwrite") && i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--overwrite"_s) && i < args.size() - 1) {
     i++;
     this->AddCTestConfigurationOverwrite(args[i]);
-  }
-  if (this->CheckArgument(arg, "-A", "--add-notes") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-A"_s, "--add-notes") &&
+             i < args.size() - 1) {
     this->Impl->ProduceXML = true;
     this->SetTest("Notes");
     i++;
     this->SetNotesFiles(args[i].c_str());
+    return true;
   }
 
-  const std::string noTestsPrefix = "--no-tests=";
+  cm::string_view noTestsPrefix = "--no-tests=";
   if (cmHasPrefix(arg, noTestsPrefix)) {
-    const std::string noTestsMode = arg.substr(noTestsPrefix.length());
+    cm::string_view noTestsMode =
+      cm::string_view(arg).substr(noTestsPrefix.length());
     if (noTestsMode == "error") {
       this->Impl->NoTestsMode = cmCTest::NoTests::Error;
     } else if (noTestsMode != "ignore") {
-      errormsg = "'--no-tests=' given unknown value '" + noTestsMode + "'";
+      errormsg =
+        cmStrCat("'--no-tests=' given unknown value '", noTestsMode, '\'');
       return false;
     } else {
       this->Impl->NoTestsMode = cmCTest::NoTests::Ignore;
@@ -2072,34 +2064,32 @@
   }
 
   // options that control what tests are run
-  if (this->CheckArgument(arg, "-I", "--tests-information") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-I"_s, "--tests-information") &&
+           i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("TestsToRunInformation",
                                                 args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation",
                                                     args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-U", "--union")) {
+  } else if (this->CheckArgument(arg, "-U"_s, "--union")) {
     this->GetTestHandler()->SetPersistentOption("UseUnion", "true");
     this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true");
-  }
-  if (this->CheckArgument(arg, "-R", "--tests-regex") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-R"_s, "--tests-regex") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression",
                                                 args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression",
                                                     args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-L", "--label-regex") && i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-L"_s, "--label-regex") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("LabelRegularExpression",
                                                 args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption("LabelRegularExpression",
                                                     args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-LE", "--label-exclude") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-LE"_s, "--label-exclude") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption(
       "ExcludeLabelRegularExpression", args[i].c_str());
@@ -2107,8 +2097,8 @@
       "ExcludeLabelRegularExpression", args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "-E", "--exclude-regex") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-E"_s, "--exclude-regex") &&
+           i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression",
                                                 args[i].c_str());
@@ -2116,24 +2106,22 @@
                                                     args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "-FA", "--fixture-exclude-any") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "-FA"_s, "--fixture-exclude-any") &&
+           i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureRegularExpression", args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption(
       "ExcludeFixtureRegularExpression", args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-FS", "--fixture-exclude-setup") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-FS"_s, "--fixture-exclude-setup") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureSetupRegularExpression", args[i].c_str());
     this->GetMemCheckHandler()->SetPersistentOption(
       "ExcludeFixtureSetupRegularExpression", args[i].c_str());
-  }
-  if (this->CheckArgument(arg, "-FC", "--fixture-exclude-cleanup") &&
-      i < args.size() - 1) {
+  } else if (this->CheckArgument(arg, "-FC"_s, "--fixture-exclude-cleanup") &&
+             i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption(
       "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
@@ -2141,8 +2129,8 @@
       "ExcludeFixtureCleanupRegularExpression", args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "--resource-spec-file") &&
-      i < args.size() - 1) {
+  else if (this->CheckArgument(arg, "--resource-spec-file"_s) &&
+           i < args.size() - 1) {
     i++;
     this->GetTestHandler()->SetPersistentOption("ResourceSpecFile",
                                                 args[i].c_str());
@@ -2150,7 +2138,7 @@
                                                     args[i].c_str());
   }
 
-  if (this->CheckArgument(arg, "--rerun-failed")) {
+  else if (this->CheckArgument(arg, "--rerun-failed"_s)) {
     this->GetTestHandler()->SetPersistentOption("RerunFailed", "true");
     this->GetMemCheckHandler()->SetPersistentOption("RerunFailed", "true");
   }
@@ -2202,7 +2190,7 @@
                                     bool& SRArgumentSpecified)
 {
   std::string arg = args[i];
-  if (this->CheckArgument(arg, "-SP", "--script-new-process") &&
+  if (this->CheckArgument(arg, "-SP"_s, "--script-new-process") &&
       i < args.size() - 1) {
     this->Impl->RunConfigurationScript = true;
     i++;
@@ -2213,7 +2201,8 @@
     }
   }
 
-  if (this->CheckArgument(arg, "-SR", "--script-run") && i < args.size() - 1) {
+  if (this->CheckArgument(arg, "-SR"_s, "--script-run") &&
+      i < args.size() - 1) {
     SRArgumentSpecified = true;
     this->Impl->RunConfigurationScript = true;
     i++;
@@ -2221,7 +2210,7 @@
     ch->AddConfigurationScript(args[i].c_str(), true);
   }
 
-  if (this->CheckArgument(arg, "-S", "--script") && i < args.size() - 1) {
+  if (this->CheckArgument(arg, "-S"_s, "--script") && i < args.size() - 1) {
     this->Impl->RunConfigurationScript = true;
     i++;
     cmCTestScriptHandler* ch = this->GetScriptHandler();
@@ -2271,7 +2260,8 @@
 
     // --dashboard: handle a request for a dashboard
     std::string arg = args[i];
-    if (this->CheckArgument(arg, "-D", "--dashboard") && i < args.size() - 1) {
+    if (this->CheckArgument(arg, "-D"_s, "--dashboard") &&
+        i < args.size() - 1) {
       this->Impl->ProduceXML = true;
       i++;
       std::string targ = args[i];
@@ -2307,7 +2297,7 @@
     }
 
     // --extra-submit
-    if (this->CheckArgument(arg, "--extra-submit") && i < args.size() - 1) {
+    if (this->CheckArgument(arg, "--extra-submit"_s) && i < args.size() - 1) {
       this->Impl->ProduceXML = true;
       this->SetTest("Submit");
       i++;
@@ -2317,12 +2307,13 @@
     }
 
     // --build-and-test options
-    if (this->CheckArgument(arg, "--build-and-test") && i < args.size() - 1) {
+    if (this->CheckArgument(arg, "--build-and-test"_s) &&
+        i < args.size() - 1) {
       cmakeAndTest = true;
     }
 
     // --schedule-random
-    if (this->CheckArgument(arg, "--schedule-random")) {
+    if (this->CheckArgument(arg, "--schedule-random"_s)) {
       this->Impl->ScheduleType = "Random";
     }
 
@@ -2377,7 +2368,7 @@
 {
   bool success = true;
   std::string arg = args[i];
-  if (this->CheckArgument(arg, "-T", "--test-action") &&
+  if (this->CheckArgument(arg, "-T"_s, "--test-action") &&
       (i < args.size() - 1)) {
     this->Impl->ProduceXML = true;
     i++;
@@ -2409,15 +2400,15 @@
 {
   bool success = true;
   std::string arg = args[i];
-  if (this->CheckArgument(arg, "-M", "--test-model") &&
+  if (this->CheckArgument(arg, "-M"_s, "--test-model") &&
       (i < args.size() - 1)) {
     i++;
     std::string const& str = args[i];
-    if (cmSystemTools::LowerCase(str) == "nightly") {
+    if (cmSystemTools::LowerCase(str) == "nightly"_s) {
       this->SetTestModel(cmCTest::NIGHTLY);
-    } else if (cmSystemTools::LowerCase(str) == "continuous") {
+    } else if (cmSystemTools::LowerCase(str) == "continuous"_s) {
       this->SetTestModel(cmCTest::CONTINUOUS);
-    } else if (cmSystemTools::LowerCase(str) == "experimental") {
+    } else if (cmSystemTools::LowerCase(str) == "experimental"_s) {
       this->SetTestModel(cmCTest::EXPERIMENTAL);
     } else {
       success = false;
@@ -2684,7 +2675,7 @@
 
     path = "./" + *res;
     if (path.back() == '/') {
-      path = path.substr(0, path.size() - 1);
+      path.resize(path.size() - 1);
     }
   }
 
@@ -2735,7 +2726,7 @@
     std::string site = this->GetCTestConfiguration("DropSite");
     std::string location = this->GetCTestConfiguration("DropLocation");
 
-    url = cmStrCat(method.empty() ? "http" : method, "://");
+    url = cmStrCat(method.empty() ? "http" : method, "://"_s);
     if (!user.empty()) {
       url += user;
       if (!password.empty()) {
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 7f8f913..984be13 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -13,6 +13,8 @@
 #include <string>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmDuration.h"
 #include "cmProcessOutput.h"
 
@@ -140,7 +142,8 @@
 
   std::string GetTestModelString();
   static int GetTestModelFromString(const char* str);
-  static std::string CleanString(const std::string& str);
+  static std::string CleanString(const std::string& str,
+                                 std::string::size_type spos = 0);
   std::string GetCTestConfiguration(const std::string& name);
   void SetCTestConfiguration(const char* name, const char* value,
                              bool suppress = false);
@@ -506,8 +509,8 @@
                                std::vector<std::string> const& files);
 
   /** Check if the argument is the one specified */
-  bool CheckArgument(const std::string& arg, const char* varg1,
-                     const char* varg2 = nullptr);
+  static bool CheckArgument(const std::string& arg, cm::string_view varg1,
+                            const char* varg2 = nullptr);
 
   /** Output errors from a test */
   void OutputTestErrors(std::vector<char> const& process_output);
diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx
index ee89b0d..31a8692 100644
--- a/Source/cmCacheManager.cxx
+++ b/Source/cmCacheManager.cxx
@@ -77,7 +77,7 @@
     }
     while (realbuffer[0] == '/' && realbuffer[1] == '/') {
       if ((realbuffer[2] == '\\') && (realbuffer[3] == 'n')) {
-        helpString += "\n";
+        helpString += '\n';
         helpString += &realbuffer[4];
       } else {
         helpString += &realbuffer[2];
@@ -117,20 +117,20 @@
       }
     } else {
       std::ostringstream error;
-      error << "Parse error in cache file " << cacheFile;
-      error << " on line " << lineno << ". Offending entry: " << realbuffer;
+      error << "Parse error in cache file " << cacheFile << " on line "
+            << lineno << ". Offending entry: " << realbuffer;
       cmSystemTools::Error(error.str());
     }
   }
   this->CacheMajorVersion = 0;
   this->CacheMinorVersion = 0;
-  if (const std::string* cmajor =
+  if (cmProp cmajor =
         this->GetInitializedCacheValue("CMAKE_CACHE_MAJOR_VERSION")) {
     unsigned int v = 0;
     if (sscanf(cmajor->c_str(), "%u", &v) == 1) {
       this->CacheMajorVersion = v;
     }
-    if (const std::string* cminor =
+    if (cmProp cminor =
           this->GetInitializedCacheValue("CMAKE_CACHE_MINOR_VERSION")) {
       if (sscanf(cminor->c_str(), "%u", &v) == 1) {
         this->CacheMinorVersion = v;
@@ -150,8 +150,7 @@
   }
   // check to make sure the cache directory has not
   // been moved
-  const std::string* oldDir =
-    this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
+  cmProp oldDir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
   if (internal && oldDir) {
     std::string currentcwd = path;
     std::string oldcwd = *oldDir;
@@ -159,8 +158,7 @@
     currentcwd += "/CMakeCache.txt";
     oldcwd += "/CMakeCache.txt";
     if (!cmSystemTools::SameFile(oldcwd, currentcwd)) {
-      const std::string* dir =
-        this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
+      cmProp dir = this->GetInitializedCacheValue("CMAKE_CACHEFILE_DIR");
       std::ostringstream message;
       message << "The current CMakeCache.txt directory " << currentcwd
               << " is different than the directory " << (dir ? *dir : "")
@@ -210,7 +208,7 @@
                                           cmMessenger* messenger)
 {
   for (const char** p = cmCacheManager::PersistentProperties; *p; ++p) {
-    if (const char* value = i.GetProperty(*p)) {
+    if (cmProp value = i.GetProperty(*p)) {
       std::string helpstring =
         cmStrCat(*p, " property for variable: ", i.GetName());
       cmCacheManager::OutputHelpString(os, helpstring);
@@ -218,9 +216,9 @@
       std::string key = cmStrCat(i.GetName(), '-', *p);
       cmCacheManager::OutputKey(os, key);
       os << ":INTERNAL=";
-      cmCacheManager::OutputValue(os, value);
-      os << "\n";
-      cmCacheManager::OutputNewlineTruncationWarning(os, key, value,
+      cmCacheManager::OutputValue(os, *value);
+      os << '\n';
+      cmCacheManager::OutputNewlineTruncationWarning(os, key, *value,
                                                      messenger);
     }
   }
@@ -270,31 +268,29 @@
 
   /* clang-format off */
   fout << "# This is the CMakeCache file.\n"
-       << "# For build in directory: " << currentcwd << "\n"
-       << "# It was generated by CMake: "
-       << cmSystemTools::GetCMakeCommand() << std::endl;
+          "# For build in directory: " << currentcwd << "\n"
+          "# It was generated by CMake: "
+       << cmSystemTools::GetCMakeCommand()
+       << "\n"
+          "# You can edit this file to change values found and used by cmake."
+          "\n"
+          "# If you do not want to change any of the values, simply exit the "
+          "editor.\n"
+          "# If you do want to change a value, simply edit, save, and exit "
+          "the editor.\n"
+          "# The syntax for the file is as follows:\n"
+          "# KEY:TYPE=VALUE\n"
+          "# KEY is the name of a variable in the cache.\n"
+          "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!."
+          "\n"
+          "# VALUE is the current value for the KEY.\n"
+          "\n"
+          "########################\n"
+          "# EXTERNAL cache entries\n"
+          "########################\n"
+          "\n";
   /* clang-format on */
 
-  /* clang-format off */
-  fout << "# You can edit this file to change values found and used by cmake."
-       << std::endl
-       << "# If you do not want to change any of the values, simply exit the "
-       "editor." << std::endl
-       << "# If you do want to change a value, simply edit, save, and exit "
-       "the editor." << std::endl
-       << "# The syntax for the file is as follows:\n"
-       << "# KEY:TYPE=VALUE\n"
-       << "# KEY is the name of a variable in the cache.\n"
-       << "# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT "
-       "TYPE!." << std::endl
-       << "# VALUE is the current value for the KEY.\n\n";
-  /* clang-format on */
-
-  fout << "########################\n";
-  fout << "# EXTERNAL cache entries\n";
-  fout << "########################\n";
-  fout << "\n";
-
   for (auto const& i : this->Cache) {
     CacheEntry const& ce = i.second;
     cmStateEnums::CacheEntryType t = ce.Type;
@@ -305,26 +301,26 @@
       */
     } else if (t != cmStateEnums::INTERNAL) {
       // Format is key:type=value
-      if (const char* help = ce.GetProperty("HELPSTRING")) {
-        cmCacheManager::OutputHelpString(fout, help);
+      if (cmProp help = ce.GetProperty("HELPSTRING")) {
+        cmCacheManager::OutputHelpString(fout, *help);
       } else {
         cmCacheManager::OutputHelpString(fout, "Missing description");
       }
       cmCacheManager::OutputKey(fout, i.first);
-      fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
+      fout << ':' << cmState::CacheEntryTypeToString(t) << '=';
       cmCacheManager::OutputValue(fout, ce.Value);
-      fout << "\n";
+      fout << '\n';
       cmCacheManager::OutputNewlineTruncationWarning(fout, i.first, ce.Value,
                                                      messenger);
-      fout << "\n";
+      fout << '\n';
     }
   }
 
-  fout << "\n";
-  fout << "########################\n";
-  fout << "# INTERNAL cache entries\n";
-  fout << "########################\n";
-  fout << "\n";
+  fout << "\n"
+          "########################\n"
+          "# INTERNAL cache entries\n"
+          "########################\n"
+          "\n";
 
   for (cmCacheManager::CacheIterator i = this->NewIterator(); !i.IsAtEnd();
        i.Next()) {
@@ -336,18 +332,18 @@
     this->WritePropertyEntries(fout, i, messenger);
     if (t == cmStateEnums::INTERNAL) {
       // Format is key:type=value
-      if (const char* help = i.GetProperty("HELPSTRING")) {
-        cmCacheManager::OutputHelpString(fout, help);
+      if (cmProp help = i.GetProperty("HELPSTRING")) {
+        cmCacheManager::OutputHelpString(fout, *help);
       }
       cmCacheManager::OutputKey(fout, i.GetName());
-      fout << ":" << cmState::CacheEntryTypeToString(t) << "=";
+      fout << ':' << cmState::CacheEntryTypeToString(t) << '=';
       cmCacheManager::OutputValue(fout, i.GetValue());
-      fout << "\n";
+      fout << '\n';
       cmCacheManager::OutputNewlineTruncationWarning(fout, i.GetName(),
                                                      i.GetValue(), messenger);
     }
   }
-  fout << "\n";
+  fout << '\n';
   fout.Close();
   std::string checkCacheFile = cmStrCat(path, "/CMakeFiles");
   cmSystemTools::MakeDirectory(checkCacheFile);
@@ -385,7 +381,9 @@
 {
   // support : in key name by double quoting
   const char* q =
-    (key.find(':') != std::string::npos || key.find("//") == 0) ? "\"" : "";
+    (key.find(':') != std::string::npos || cmHasLiteralPrefix(key, "//"))
+    ? "\""
+    : "";
   fout << q << key << q;
 }
 
@@ -430,7 +428,7 @@
         fout << "\\n";
       }
       oneLine = helpString.substr(pos, i - pos);
-      fout << oneLine << "\n";
+      fout << oneLine << '\n';
       pos = i;
     }
   }
@@ -452,7 +450,7 @@
         fout << "\\n";
       }
       oneLine = message.substr(pos, i - pos);
-      fout << oneLine << "\n";
+      fout << oneLine << '\n';
       pos = i;
     }
   }
@@ -508,8 +506,7 @@
   return { *this, nullptr };
 }
 
-const std::string* cmCacheManager::GetInitializedCacheValue(
-  const std::string& key) const
+cmProp cmCacheManager::GetInitializedCacheValue(const std::string& key) const
 {
   auto i = this->Cache.find(key);
   if (i != this->Cache.end() && i->second.Initialized) {
@@ -520,17 +517,17 @@
 
 void cmCacheManager::PrintCache(std::ostream& out) const
 {
-  out << "=================================================" << std::endl;
-  out << "CMakeCache Contents:" << std::endl;
+  out << "=================================================\n"
+         "CMakeCache Contents:\n";
   for (auto const& i : this->Cache) {
     if (i.second.Type != cmStateEnums::INTERNAL) {
-      out << i.first << " = " << i.second.Value << std::endl;
+      out << i.first << " = " << i.second.Value << '\n';
     }
   }
-  out << "\n\n";
-  out << "To change values in the CMakeCache, " << std::endl
-      << "edit CMakeCache.txt in your output directory.\n";
-  out << "=================================================" << std::endl;
+  out << "\n\n"
+         "To change values in the CMakeCache, \n"
+         "edit CMakeCache.txt in your output directory.\n"
+         "=================================================\n";
 }
 
 void cmCacheManager::AddCacheEntry(const std::string& key, const char* value,
@@ -619,17 +616,15 @@
   return this->Properties.GetKeys();
 }
 
-const char* cmCacheManager::CacheEntry::GetProperty(
-  const std::string& prop) const
+cmProp cmCacheManager::CacheEntry::GetProperty(const std::string& prop) const
 {
   if (prop == "TYPE") {
-    return cmState::CacheEntryTypeToString(this->Type).c_str();
+    return &cmState::CacheEntryTypeToString(this->Type);
   }
   if (prop == "VALUE") {
-    return this->Value.c_str();
+    return &this->Value;
   }
-  cmProp retVal = this->Properties.GetPropertyValue(prop);
-  return retVal ? retVal->c_str() : nullptr;
+  return this->Properties.GetPropertyValue(prop);
 }
 
 void cmCacheManager::CacheEntry::SetProperty(const std::string& prop,
@@ -663,7 +658,7 @@
   }
 }
 
-const char* cmCacheManager::CacheIterator::GetProperty(
+cmProp cmCacheManager::CacheIterator::GetProperty(
   const std::string& prop) const
 {
   if (!this->IsAtEnd()) {
@@ -692,8 +687,8 @@
 bool cmCacheManager::CacheIterator::GetPropertyAsBool(
   const std::string& prop) const
 {
-  if (const char* value = this->GetProperty(prop)) {
-    return cmIsOn(value);
+  if (cmProp value = this->GetProperty(prop)) {
+    return cmIsOn(*value);
   }
   return false;
 }
diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h
index d8be991..3db76a9 100644
--- a/Source/cmCacheManager.h
+++ b/Source/cmCacheManager.h
@@ -37,7 +37,7 @@
     cmStateEnums::CacheEntryType Type = cmStateEnums::UNINITIALIZED;
     cmPropertyMap Properties;
     std::vector<std::string> GetPropertyList() const;
-    const char* GetProperty(const std::string&) const;
+    cmProp GetProperty(const std::string&) const;
     void SetProperty(const std::string& property, const char* value);
     void AppendProperty(const std::string& property, const std::string& value,
                         bool asString = false);
@@ -54,7 +54,7 @@
     void Next();
     std::string GetName() const { return this->Position->first; }
     std::vector<std::string> GetPropertyList() const;
-    const char* GetProperty(const std::string&) const;
+    cmProp GetProperty(const std::string&) const;
     bool GetPropertyAsBool(const std::string&) const;
     bool PropertyExists(const std::string&) const;
     void SetProperty(const std::string& property, const char* value);
@@ -121,19 +121,19 @@
   int GetSize() { return static_cast<int>(this->Cache.size()); }
 
   //! Get a value from the cache given a key
-  const std::string* GetInitializedCacheValue(const std::string& key) const;
+  cmProp GetInitializedCacheValue(const std::string& key) const;
 
-  const char* GetCacheEntryValue(const std::string& key)
+  cmProp GetCacheEntryValue(const std::string& key)
   {
     cmCacheManager::CacheIterator it = this->GetCacheIterator(key);
     if (it.IsAtEnd()) {
       return nullptr;
     }
-    return it.GetValue().c_str();
+    return &it.GetValue();
   }
 
-  const char* GetCacheEntryProperty(std::string const& key,
-                                    std::string const& propName)
+  cmProp GetCacheEntryProperty(std::string const& key,
+                               std::string const& propName)
   {
     return this->GetCacheIterator(key).GetProperty(propName);
   }
diff --git a/Source/cmCallVisualStudioMacro.cxx b/Source/cmCallVisualStudioMacro.cxx
index 9e152ff..94b6e18 100644
--- a/Source/cmCallVisualStudioMacro.cxx
+++ b/Source/cmCallVisualStudioMacro.cxx
@@ -43,8 +43,7 @@
       if (LogErrorsAsMessages) {                                              \
         std::ostringstream _hresult_oss;                                      \
         _hresult_oss.flags(std::ios::hex);                                    \
-        _hresult_oss << context << " failed HRESULT, hr = 0x" << hr           \
-                     << std::endl;                                            \
+        _hresult_oss << context << " failed HRESULT, hr = 0x" << hr << '\n';  \
         _hresult_oss.flags(std::ios::dec);                                    \
         _hresult_oss << __FILE__ << "(" << __LINE__ << ")";                   \
         cmSystemTools::Message(_hresult_oss.str());                           \
@@ -98,32 +97,37 @@
                          DISPATCH_METHOD, &params, &result, &excep, &arg);
 
       std::ostringstream oss;
-      oss << std::endl;
-      oss << "Invoke(ExecuteCommand)" << std::endl;
-      oss << "  Macro: " << macro << std::endl;
-      oss << "  Args: " << args << std::endl;
+      /* clang-format off */
+      oss << "\nInvoke(ExecuteCommand)\n"
+             "  Macro: " << macro << "\n"
+             "  Args: " << args << '\n';
+      /* clang-format on */
 
       if (DISP_E_EXCEPTION == hr) {
-        oss << "DISP_E_EXCEPTION EXCEPINFO:" << excep.wCode << std::endl;
-        oss << "  wCode: " << excep.wCode << std::endl;
-        oss << "  wReserved: " << excep.wReserved << std::endl;
+        /* clang-format off */
+        oss << "DISP_E_EXCEPTION EXCEPINFO:" << excep.wCode << "\n"
+               "  wCode: " << excep.wCode << "\n"
+               "  wReserved: " << excep.wReserved << '\n';
+        /* clang-format on */
         if (excep.bstrSource) {
           oss << "  bstrSource: " << (const char*)(_bstr_t)excep.bstrSource
-              << std::endl;
+              << '\n';
         }
         if (excep.bstrDescription) {
           oss << "  bstrDescription: "
-              << (const char*)(_bstr_t)excep.bstrDescription << std::endl;
+              << (const char*)(_bstr_t)excep.bstrDescription << '\n';
         }
         if (excep.bstrHelpFile) {
           oss << "  bstrHelpFile: " << (const char*)(_bstr_t)excep.bstrHelpFile
-              << std::endl;
+              << '\n';
         }
-        oss << "  dwHelpContext: " << excep.dwHelpContext << std::endl;
-        oss << "  pvReserved: " << excep.pvReserved << std::endl;
-        oss << "  pfnDeferredFillIn: "
-            << reinterpret_cast<void*>(excep.pfnDeferredFillIn) << std::endl;
-        oss << "  scode: " << excep.scode << std::endl;
+        /* clang-format off */
+        oss << "  dwHelpContext: " << excep.dwHelpContext << "\n"
+               "  pvReserved: " << excep.pvReserved << "\n"
+               "  pfnDeferredFillIn: "
+            << reinterpret_cast<void*>(excep.pfnDeferredFillIn) << "\n"
+               "  scode: " << excep.scode << '\n';
+        /* clang-format on */
       }
 
       std::string exstr(oss.str());
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 11570d6..8d27699 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -1200,7 +1200,8 @@
     // CMP0003 so put it in OldUserFlagItems, if it is not a -l
     // or -Wl,-l (-framework -pthread), then allow it without a
     // CMP0003 as -L will not affect those other linker flags
-    if (item.Value.find("-l") == 0 || item.Value.find("-Wl,-l") == 0) {
+    if (cmHasLiteralPrefix(item.Value, "-l") ||
+        cmHasLiteralPrefix(item.Value, "-Wl,-l")) {
       // This is a linker option provided by the user.
       this->OldUserFlagItems.push_back(item.Value);
     }
@@ -1796,11 +1797,11 @@
       // support or if using the link path as an rpath.
       if (use_build_rpath) {
         std::string d = ri;
-        if (!rootPath.empty() && d.find(rootPath) == 0) {
-          d = d.substr(rootPath.size());
-        } else if (stagePath && *stagePath && d.find(stagePath) == 0) {
-          std::string suffix = d.substr(strlen(stagePath));
-          d = cmStrCat(installPrefix, '/', suffix);
+        if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
+          d.erase(0, rootPath.size());
+        } else if (stagePath && *stagePath && cmHasPrefix(d, stagePath)) {
+          d.erase(0, strlen(stagePath));
+          d = cmStrCat(installPrefix, '/', d);
           cmSystemTools::ConvertToUnixSlashes(d);
         } else if (use_relative_build_rpath) {
           // If expansion of the $ORIGIN token is supported and permitted per
@@ -1827,11 +1828,11 @@
             !cmSystemTools::IsSubDirectory(ri, topSourceDir) &&
             !cmSystemTools::IsSubDirectory(ri, topBinaryDir)) {
           std::string d = ri;
-          if (!rootPath.empty() && d.find(rootPath) == 0) {
-            d = d.substr(rootPath.size());
-          } else if (stagePath && *stagePath && d.find(stagePath) == 0) {
-            std::string suffix = d.substr(strlen(stagePath));
-            d = cmStrCat(installPrefix, '/', suffix);
+          if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
+            d.erase(0, rootPath.size());
+          } else if (stagePath && *stagePath && cmHasPrefix(d, stagePath)) {
+            d.erase(0, strlen(stagePath));
+            d = cmStrCat(installPrefix, '/', d);
             cmSystemTools::ConvertToUnixSlashes(d);
           }
           if (emitted.insert(d).second) {
diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index fda687f..bf11022 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -494,12 +494,12 @@
       if (this->IsKeyword(keyDEFINED, *arg) && argP1 != newArgs.end()) {
         size_t argP1len = argP1->GetValue().size();
         bool bdef = false;
-        if (argP1len > 4 && argP1->GetValue().substr(0, 4) == "ENV{" &&
+        if (argP1len > 4 && cmHasLiteralPrefix(argP1->GetValue(), "ENV{") &&
             argP1->GetValue().operator[](argP1len - 1) == '}') {
           std::string env = argP1->GetValue().substr(4, argP1len - 5);
           bdef = cmSystemTools::HasEnv(env);
         } else if (argP1len > 6 &&
-                   argP1->GetValue().substr(0, 6) == "CACHE{" &&
+                   cmHasLiteralPrefix(argP1->GetValue(), "CACHE{") &&
                    argP1->GetValue().operator[](argP1len - 1) == '}') {
           std::string cache = argP1->GetValue().substr(6, argP1len - 7);
           bdef =
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index da04396..9c26f61 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -101,29 +101,23 @@
   this->SrcFileSignature = true;
 
   cmStateEnums::TargetType targetType = cmStateEnums::EXECUTABLE;
-  const char* tt =
-    this->Makefile->GetDefinition("CMAKE_TRY_COMPILE_TARGET_TYPE");
-  if (!isTryRun && tt && *tt) {
-    if (strcmp(tt, cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) ==
-        0) {
+  const std::string* tt =
+    this->Makefile->GetDef("CMAKE_TRY_COMPILE_TARGET_TYPE");
+  if (!isTryRun && tt && !tt->empty()) {
+    if (*tt == cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE)) {
       targetType = cmStateEnums::EXECUTABLE;
-    } else if (strcmp(tt,
-                      cmState::GetTargetTypeName(
-                        cmStateEnums::STATIC_LIBRARY)) == 0) {
+    } else if (*tt ==
+               cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY)) {
       targetType = cmStateEnums::STATIC_LIBRARY;
     } else {
       this->Makefile->IssueMessage(
         MessageType::FATAL_ERROR,
-        std::string("Invalid value '") + tt +
-          "' for "
-          "CMAKE_TRY_COMPILE_TARGET_TYPE.  Only "
-          "'" +
-          cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE) +
-          "' and "
-          "'" +
-          cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY) +
-          "' "
-          "are allowed.");
+        cmStrCat("Invalid value '", *tt,
+                 "' for CMAKE_TRY_COMPILE_TARGET_TYPE.  Only '",
+                 cmState::GetTargetTypeName(cmStateEnums::EXECUTABLE),
+                 "' and '",
+                 cmState::GetTargetTypeName(cmStateEnums::STATIC_LIBRARY),
+                 "' are allowed."));
       return -1;
     }
   }
@@ -296,12 +290,10 @@
           default:
             this->Makefile->IssueMessage(
               MessageType::FATAL_ERROR,
-              "Only libraries may be used as try_compile or try_run IMPORTED "
-              "LINK_LIBRARIES.  Got " +
-                std::string(tgt->GetName()) +
-                " of "
-                "type " +
-                cmState::GetTargetTypeName(tgt->GetType()) + ".");
+              cmStrCat("Only libraries may be used as try_compile or try_run "
+                       "IMPORTED LINK_LIBRARIES.  Got ",
+                       tgt->GetName(), " of type ",
+                       cmState::GetTargetTypeName(tgt->GetType()), "."));
             return -1;
         }
         if (tgt->IsImported()) {
diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx
index 129a5f7..d4e8da6 100644
--- a/Source/cmDepends.cxx
+++ b/Source/cmDepends.cxx
@@ -2,7 +2,6 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmDepends.h"
 
-#include <sstream>
 #include <utility>
 
 #include "cmsys/FStream.hxx"
@@ -81,16 +80,14 @@
 {
   // Print verbose output.
   if (this->Verbose) {
-    std::ostringstream msg;
-    msg << "Clearing dependencies in \"" << file << "\"." << std::endl;
-    cmSystemTools::Stdout(msg.str());
+    cmSystemTools::Stdout(
+      cmStrCat("Clearing dependencies in \"", file, "\".\n"));
   }
 
   // Write an empty dependency file.
   cmGeneratedFileStream depFileStream(file);
   depFileStream << "# Empty dependencies file\n"
-                << "# This may be replaced when dependencies are built."
-                << std::endl;
+                   "# This may be replaced when dependencies are built.\n";
 }
 
 bool cmDepends::WriteDependencies(const std::set<std::string>& /*unused*/,
@@ -172,10 +169,9 @@
 
       // Print verbose output.
       if (this->Verbose) {
-        std::ostringstream msg;
-        msg << "Dependee \"" << dependee << "\" does not exist for depender \""
-            << depender << "\"." << std::endl;
-        cmSystemTools::Stdout(msg.str());
+        cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
+                                       "\" does not exist for depender \"",
+                                       depender, "\".\n"));
       }
     } else if (dependerExists) {
       // The dependee and depender both exist.  Compare file times.
@@ -185,10 +181,9 @@
 
         // Print verbose output.
         if (this->Verbose) {
-          std::ostringstream msg;
-          msg << "Dependee \"" << dependee << "\" is newer than depender \""
-              << depender << "\"." << std::endl;
-          cmSystemTools::Stdout(msg.str());
+          cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
+                                         "\" is newer than depender \"",
+                                         depender, "\".\n"));
         }
       }
     } else {
@@ -200,11 +195,9 @@
 
         // Print verbose output.
         if (this->Verbose) {
-          std::ostringstream msg;
-          msg << "Dependee \"" << dependee
-              << "\" is newer than depends file \"" << internalDependsFileName
-              << "\"." << std::endl;
-          cmSystemTools::Stdout(msg.str());
+          cmSystemTools::Stdout(cmStrCat("Dependee \"", dependee,
+                                         "\" is newer than depends file \"",
+                                         internalDependsFileName, "\".\n"));
         }
       }
     }
diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx
index e30d959..01bb6ed 100644
--- a/Source/cmDependsC.cxx
+++ b/Source/cmDependsC.cxx
@@ -212,17 +212,17 @@
   // convert the dependencies to paths relative to the home output
   // directory.  We must do the same here.
   std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i);
-  internalDepends << obj_i << std::endl;
+  internalDepends << obj_i << '\n';
 
   for (std::string const& dep : dependencies) {
     makeDepends << obj_m << ": "
                 << cmSystemTools::ConvertToOutputPath(
                      this->LocalGenerator->MaybeConvertToRelativePath(binDir,
                                                                       dep))
-                << std::endl;
-    internalDepends << " " << dep << std::endl;
+                << '\n';
+    internalDepends << ' ' << dep << '\n';
   }
-  makeDepends << std::endl;
+  makeDepends << '\n';
 
   return true;
 }
@@ -264,19 +264,19 @@
       // file doesn't exist, check that the regular expressions
       // haven't changed
       else if (!res) {
-        if (line.find(INCLUDE_REGEX_LINE_MARKER) == 0) {
+        if (cmHasLiteralPrefix(line, INCLUDE_REGEX_LINE_MARKER)) {
           if (line != this->IncludeRegexLineString) {
             return;
           }
-        } else if (line.find(INCLUDE_REGEX_SCAN_MARKER) == 0) {
+        } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_SCAN_MARKER)) {
           if (line != this->IncludeRegexScanString) {
             return;
           }
-        } else if (line.find(INCLUDE_REGEX_COMPLAIN_MARKER) == 0) {
+        } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_COMPLAIN_MARKER)) {
           if (line != this->IncludeRegexComplainString) {
             return;
           }
-        } else if (line.find(INCLUDE_REGEX_TRANSFORM_MARKER) == 0) {
+        } else if (cmHasLiteralPrefix(line, INCLUDE_REGEX_TRANSFORM_MARKER)) {
           if (line != this->IncludeRegexTransformString) {
             return;
           }
@@ -312,17 +312,17 @@
 
   for (auto const& fileIt : this->FileCache) {
     if (fileIt.second.Used) {
-      cacheOut << fileIt.first << std::endl;
+      cacheOut << fileIt.first << '\n';
 
       for (UnscannedEntry const& inc : fileIt.second.UnscannedEntries) {
-        cacheOut << inc.FileName << std::endl;
+        cacheOut << inc.FileName << '\n';
         if (inc.QuotedLocation.empty()) {
-          cacheOut << "-" << std::endl;
+          cacheOut << '-' << '\n';
         } else {
-          cacheOut << inc.QuotedLocation << std::endl;
+          cacheOut << inc.QuotedLocation << '\n';
         }
       }
-      cacheOut << std::endl;
+      cacheOut << '\n';
     }
   }
 }
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index 983a684..666306c 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -185,7 +185,7 @@
   fiStream << "provides\n";
   std::set<std::string> const& provides = this->Internal->TargetProvides;
   for (std::string const& i : provides) {
-    fiStream << " " << i << "\n";
+    fiStream << ' ' << i << '\n';
   }
 
   // Create a script to clean the modules.
@@ -202,14 +202,14 @@
       std::string mod_lower = cmStrCat(mod_dir, '/');
       cmFortranModuleAppendUpperLower(i, mod_upper, mod_lower);
       std::string stamp = cmStrCat(stamp_dir, '/', i, ".stamp");
-      fcStream << "\n";
-      fcStream << "  \""
+      fcStream << "\n"
+                  "  \""
                << this->MaybeConvertToRelativePath(currentBinDir, mod_lower)
-               << "\"\n";
-      fcStream << "  \""
+               << "\"\n"
+                  "  \""
                << this->MaybeConvertToRelativePath(currentBinDir, mod_upper)
-               << "\"\n";
-      fcStream << "  \""
+               << "\"\n"
+                  "  \""
                << this->MaybeConvertToRelativePath(currentBinDir, stamp)
                << "\"\n";
     }
@@ -326,16 +326,15 @@
   std::string binDir = this->LocalGenerator->GetBinaryDirectory();
   std::string obj_i = this->MaybeConvertToRelativePath(binDir, obj);
   std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i);
-  internalDepends << obj_i << std::endl;
-  internalDepends << " " << src << std::endl;
+  internalDepends << obj_i << "\n " << src << '\n';
   for (std::string const& i : info.Includes) {
     makeDepends << obj_m << ": "
                 << cmSystemTools::ConvertToOutputPath(
                      this->MaybeConvertToRelativePath(binDir, i))
-                << std::endl;
-    internalDepends << " " << i << std::endl;
+                << '\n';
+    internalDepends << ' ' << i << '\n';
   }
-  makeDepends << std::endl;
+  makeDepends << '\n';
 
   // Write module requirements to the output stream.
   for (std::string const& i : info.Requires) {
@@ -354,7 +353,7 @@
       // This module is known.  Depend on its timestamp file.
       std::string stampFile = cmSystemTools::ConvertToOutputPath(
         this->MaybeConvertToRelativePath(binDir, required->second));
-      makeDepends << obj_m << ": " << stampFile << "\n";
+      makeDepends << obj_m << ": " << stampFile << '\n';
     } else {
       // This module is not known to CMake.  Try to locate it where
       // the compiler will and depend on that.
@@ -362,7 +361,7 @@
       if (this->FindModule(i, module)) {
         module = cmSystemTools::ConvertToOutputPath(
           this->MaybeConvertToRelativePath(binDir, module));
-        makeDepends << obj_m << ": " << module << "\n";
+        makeDepends << obj_m << ": " << module << '\n';
       }
     }
   }
@@ -391,7 +390,7 @@
         cmSystemTools::ConvertToOutputPath(stampFile);
 
       makeDepends << obj_m << ".provides.build"
-                  << ": " << stampFileForMake << "\n";
+                  << ": " << stampFileForMake << '\n';
       // Note that when cmake_copy_f90_mod finds that a module file
       // and the corresponding stamp file have no differences, the stamp
       // file is not updated. In such case the stamp file will be always
@@ -399,15 +398,15 @@
       // on each new build. This is expected behavior for incremental
       // builds and can not be changed without preforming recursive make
       // calls that would considerably slow down the building process.
-      makeDepends << stampFileForMake << ": " << obj_m << "\n";
+      makeDepends << stampFileForMake << ": " << obj_m << '\n';
       makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod " << modFile
-                  << " " << stampFileForShell;
+                  << ' ' << stampFileForShell;
       cmMakefile* mf = this->LocalGenerator->GetMakefile();
       const char* cid = mf->GetDefinition("CMAKE_Fortran_COMPILER_ID");
       if (cid && *cid) {
-        makeDepends << " " << cid;
+        makeDepends << ' ' << cid;
       }
-      makeDepends << "\n";
+      makeDepends << '\n';
     }
     makeDepends << obj_m << ".provides.build:\n";
     // After copying the modules update the timestamp file.
diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx
index 561e830..a2b4d60 100644
--- a/Source/cmExportBuildAndroidMKGenerator.cxx
+++ b/Source/cmExportBuildAndroidMKGenerator.cxx
@@ -118,13 +118,13 @@
           } else {
             bool relpath = false;
             if (type == cmExportBuildAndroidMKGenerator::INSTALL) {
-              relpath = lib.substr(0, 3) == "../";
+              relpath = cmHasLiteralPrefix(lib, "../");
             }
             // check for full path or if it already has a -l, or
             // in the case of an install check for relative paths
             // if it is full or a link library then use string directly
             if (cmSystemTools::FileIsFullPath(lib) ||
-                lib.substr(0, 2) == "-l" || relpath) {
+                cmHasLiteralPrefix(lib, "-l") || relpath) {
               ldlibs += " " + lib;
               // if it is not a path and does not have a -l then add -l
             } else if (!lib.empty()) {
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index b7cc193..f31759d 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -24,6 +24,7 @@
 #include "cmMessageType.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 
@@ -183,6 +184,28 @@
     return false;
   }
 
+  // if cmExportBuildFileGenerator is already defined for the file
+  // and APPEND is not specified, if CMP0103 is OLD ignore previous definition
+  // else raise an error
+  if (gg->GetExportedTargetsFile(fname) != nullptr) {
+    switch (mf.GetPolicyStatus(cmPolicies::CMP0103)) {
+      case cmPolicies::WARN:
+        mf.IssueMessage(
+          MessageType::AUTHOR_WARNING,
+          cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0103), '\n',
+                   "export() command already specified for the file\n  ",
+                   arguments.Filename, "\nDid you miss 'APPEND' keyword?"));
+        CM_FALLTHROUGH;
+      case cmPolicies::OLD:
+        break;
+      default:
+        status.SetError(cmStrCat("command already specified for the file\n  ",
+                                 arguments.Filename,
+                                 "\nDid you miss 'APPEND' keyword?"));
+        return false;
+    }
+  }
+
   // Setup export file generation.
   std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr;
   if (android) {
@@ -198,7 +221,6 @@
   } else {
     ebfg->SetTargets(targets);
   }
-  mf.AddExportBuildFileGenerator(ebfg.get());
   ebfg->SetExportOld(arguments.ExportOld);
 
   // Compute the set of configurations exported.
@@ -211,10 +233,11 @@
     ebfg->AddConfiguration(ct);
   }
   if (exportSet != nullptr) {
-    gg->AddBuildExportExportSet(std::move(ebfg));
+    gg->AddBuildExportExportSet(ebfg.get());
   } else {
-    gg->AddBuildExportSet(std::move(ebfg));
+    gg->AddBuildExportSet(ebfg.get());
   }
+  mf.AddExportBuildFileGenerator(std::move(ebfg));
 
   return true;
 }
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 003019a..ea31417 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -276,8 +276,7 @@
                 << "\"\nhowever it is also "
                    "a subdirectory of the "
                 << (inBinary ? "build" : "source") << " tree:\n    \""
-                << (inBinary ? topBinaryDir : topSourceDir) << "\""
-                << std::endl;
+                << (inBinary ? topBinaryDir : topSourceDir) << "\"\n";
               target->GetLocalGenerator()->IssueMessage(
                 MessageType::AUTHOR_WARNING, s.str());
               CM_FALLTHROUGH;
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index 3df6a5c..807ebed 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -97,9 +97,9 @@
 
     properties[p] = target->GetProperty(p);
 
-    if (p.find("IMPORTED_LINK_INTERFACE_LIBRARIES") == 0 ||
-        p.find("IMPORTED_LINK_DEPENDENT_LIBRARIES") == 0 ||
-        p.find("INTERFACE_LINK_LIBRARIES") == 0) {
+    if (cmHasLiteralPrefix(p, "IMPORTED_LINK_INTERFACE_LIBRARIES") ||
+        cmHasLiteralPrefix(p, "IMPORTED_LINK_DEPENDENT_LIBRARIES") ||
+        cmHasLiteralPrefix(p, "INTERFACE_LINK_LIBRARIES")) {
       std::string evalResult =
         this->FindTargets(p, target, std::string(), emitted);
 
diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx
index b710467..42fd0ea 100644
--- a/Source/cmExtraCodeBlocksGenerator.cxx
+++ b/Source/cmExtraCodeBlocksGenerator.cxx
@@ -218,7 +218,7 @@
     // Convert
     for (std::string const& listFile : listFiles) {
       // don't put cmake's own files into the project (#12110):
-      if (listFile.find(cmSystemTools::GetCMakeRoot()) == 0) {
+      if (cmHasPrefix(listFile, cmSystemTools::GetCMakeRoot())) {
         continue;
       }
 
@@ -301,11 +301,11 @@
         case cmStateEnums::UTILITY:
           // Add all utility targets, except the Nightly/Continuous/
           // Experimental-"sub"targets as e.g. NightlyStart
-          if (((targetName.find("Nightly") == 0) &&
+          if ((cmHasLiteralPrefix(targetName, "Nightly") &&
                (targetName != "Nightly")) ||
-              ((targetName.find("Continuous") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Continuous") &&
                (targetName != "Continuous")) ||
-              ((targetName.find("Experimental") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Experimental") &&
                (targetName != "Experimental"))) {
             break;
           }
diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx
index 8ab30c0..737b0e5 100644
--- a/Source/cmExtraEclipseCDT4Generator.cxx
+++ b/Source/cmExtraEclipseCDT4Generator.cxx
@@ -187,10 +187,10 @@
     return;
   }
 
-  fout << "eclipse.preferences.version=1" << std::endl;
+  fout << "eclipse.preferences.version=1\n";
   const char* encoding = mf->GetDefinition("CMAKE_ECLIPSE_RESOURCE_ENCODING");
   if (encoding) {
-    fout << "encoding/<project>=" << encoding << std::endl;
+    fout << "encoding/<project>=" << encoding << '\n';
   }
 }
 
@@ -415,9 +415,9 @@
     xml.Element("nature", n);
   }
 
-  if (const char* extraNaturesProp =
+  if (cmProp extraNaturesProp =
         mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_NATURES")) {
-    std::vector<std::string> extraNatures = cmExpandedList(extraNaturesProp);
+    std::vector<std::string> extraNatures = cmExpandedList(*extraNaturesProp);
     for (std::string const& n : extraNatures) {
       xml.Element("nature", n);
     }
@@ -936,11 +936,11 @@
         case cmStateEnums::UTILITY:
           // Add all utility targets, except the Nightly/Continuous/
           // Experimental-"sub"targets as e.g. NightlyStart
-          if (((targetName.find("Nightly") == 0) &&
+          if ((cmHasLiteralPrefix(targetName, "Nightly") &&
                (targetName != "Nightly")) ||
-              ((targetName.find("Continuous") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Continuous") &&
                (targetName != "Continuous")) ||
-              ((targetName.find("Experimental") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Experimental") &&
                (targetName != "Experimental"))) {
             break;
           }
@@ -1033,9 +1033,9 @@
   xml.EndElement(); // storageModule
 
   // Append additional cproject contents without applying any XML formatting
-  if (const char* extraCProjectContents =
+  if (cmProp extraCProjectContents =
         mf->GetState()->GetGlobalProperty("ECLIPSE_EXTRA_CPROJECT_CONTENTS")) {
-    fout << extraCProjectContents;
+    fout << *extraCProjectContents;
   }
 
   xml.EndElement(); // cproject
diff --git a/Source/cmExtraKateGenerator.cxx b/Source/cmExtraKateGenerator.cxx
index 3a22846..271bbee 100644
--- a/Source/cmExtraKateGenerator.cxx
+++ b/Source/cmExtraKateGenerator.cxx
@@ -144,11 +144,11 @@
         case cmStateEnums::UTILITY:
           // Add all utility targets, except the Nightly/Continuous/
           // Experimental-"sub"targets as e.g. NightlyStart
-          if (((targetName.find("Nightly") == 0) &&
+          if ((cmHasLiteralPrefix(targetName, "Nightly") &&
                (targetName != "Nightly")) ||
-              ((targetName.find("Continuous") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Continuous") &&
                (targetName != "Continuous")) ||
-              ((targetName.find("Experimental") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Experimental") &&
                (targetName != "Experimental"))) {
             break;
           }
diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx
index 413449c..5b136e2 100644
--- a/Source/cmExtraSublimeTextGenerator.cxx
+++ b/Source/cmExtraSublimeTextGenerator.cxx
@@ -199,11 +199,11 @@
         case cmStateEnums::UTILITY:
           // Add all utility targets, except the Nightly/Continuous/
           // Experimental-"sub"targets as e.g. NightlyStart
-          if (((targetName.find("Nightly") == 0) &&
+          if ((cmHasLiteralPrefix(targetName, "Nightly") &&
                (targetName != "Nightly")) ||
-              ((targetName.find("Continuous") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Continuous") &&
                (targetName != "Continuous")) ||
-              ((targetName.find("Experimental") == 0) &&
+              (cmHasLiteralPrefix(targetName, "Experimental") &&
                (targetName != "Experimental"))) {
             break;
           }
diff --git a/Source/cmFileAPICache.cxx b/Source/cmFileAPICache.cxx
index 639df52..5d2ddf9 100644
--- a/Source/cmFileAPICache.cxx
+++ b/Source/cmFileAPICache.cxx
@@ -94,7 +94,8 @@
 {
   Json::Value property = Json::objectValue;
   property["name"] = prop;
-  property["value"] = this->State->GetCacheEntryProperty(name, prop);
+  cmProp p = this->State->GetCacheEntryProperty(name, prop);
+  property["value"] = p ? *p : "";
   return property;
 }
 }
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 8b450d0..4603b13 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -2327,12 +2327,9 @@
     path += "/cmake.lock";
   }
 
-  if (!cmsys::SystemTools::FileIsFullPath(path)) {
-    path = status.GetMakefile().GetCurrentSourceDirectory() + "/" + path;
-  }
-
   // Unify path (remove '//', '/../', ...)
-  path = cmSystemTools::CollapseFullPath(path);
+  path = cmSystemTools::CollapseFullPath(
+    path, status.GetMakefile().GetCurrentSourceDirectory());
 
   // Create file and directories if needed
   std::string parentDir = cmSystemTools::GetParentDirectory(path);
diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx
index 4d627bd..b5553b8 100644
--- a/Source/cmFindBase.cxx
+++ b/Source/cmFindBase.cxx
@@ -312,9 +312,9 @@
       return true;
     }
     if (cached) {
-      const char* hs =
+      cmProp hs =
         state->GetCacheEntryProperty(this->VariableName, "HELPSTRING");
-      this->VariableDocumentation = hs ? hs : "(none)";
+      this->VariableDocumentation = hs ? *hs : "(none)";
     }
   }
   return false;
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index f606002..e996327 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -1114,12 +1114,10 @@
 void cmFindPackageCommand::AppendToFoundProperty(bool found)
 {
   std::vector<std::string> foundContents;
-  const char* foundProp =
+  cmProp foundProp =
     this->Makefile->GetState()->GetGlobalProperty("PACKAGES_FOUND");
-  if (foundProp && *foundProp) {
-    std::string tmp = foundProp;
-
-    cmExpandList(tmp, foundContents, false);
+  if (foundProp && !foundProp->empty()) {
+    cmExpandList(*foundProp, foundContents, false);
     auto nameIt =
       std::find(foundContents.begin(), foundContents.end(), this->Name);
     if (nameIt != foundContents.end()) {
@@ -1128,12 +1126,10 @@
   }
 
   std::vector<std::string> notFoundContents;
-  const char* notFoundProp =
+  cmProp notFoundProp =
     this->Makefile->GetState()->GetGlobalProperty("PACKAGES_NOT_FOUND");
-  if (notFoundProp && *notFoundProp) {
-    std::string tmp = notFoundProp;
-
-    cmExpandList(tmp, notFoundContents, false);
+  if (notFoundProp && !notFoundProp->empty()) {
+    cmExpandList(*notFoundProp, notFoundContents, false);
     auto nameIt =
       std::find(notFoundContents.begin(), notFoundContents.end(), this->Name);
     if (nameIt != notFoundContents.end()) {
diff --git a/Source/cmGeneratorExpressionDAGChecker.cxx b/Source/cmGeneratorExpressionDAGChecker.cxx
index 2c73289..c860c75 100644
--- a/Source/cmGeneratorExpressionDAGChecker.cxx
+++ b/Source/cmGeneratorExpressionDAGChecker.cxx
@@ -158,8 +158,8 @@
 
 bool cmGeneratorExpressionDAGChecker::EvaluatingGenexExpression()
 {
-  return this->Property.find("TARGET_GENEX_EVAL:") == 0 ||
-    this->Property.find("GENEX_EVAL:", 0) == 0;
+  return cmHasLiteralPrefix(this->Property, "TARGET_GENEX_EVAL:") ||
+    cmHasLiteralPrefix(this->Property, "GENEX_EVAL:");
 }
 
 bool cmGeneratorExpressionDAGChecker::EvaluatingPICExpression()
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 0c1afa8..e722034 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -2023,7 +2023,7 @@
     if (cmGeneratorTarget::ImportInfo const* info =
           this->GetImportInfo(config)) {
       if (!info->NoSOName && !info->SOName.empty()) {
-        if (info->SOName.find("@rpath/") == 0) {
+        if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
           install_name_is_rpath = true;
         }
       } else {
@@ -2140,7 +2140,7 @@
         return cmSystemTools::GetFilenameName(info->Location);
       }
       // Use the soname given if any.
-      if (info->SOName.find("@rpath/") == 0) {
+      if (cmHasLiteralPrefix(info->SOName, "@rpath/")) {
         return info->SOName.substr(6);
       }
       return info->SOName;
@@ -3781,9 +3781,16 @@
   if (inserted.second) {
     std::string& createOptionList = inserted.first->second;
 
+    if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
+      createOptionList = this->Makefile->GetSafeDefinition(
+        cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
+    }
+
     const std::string createOptVar =
       cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_CREATE_PCH");
-    createOptionList = this->Makefile->GetSafeDefinition(createOptVar);
+
+    createOptionList = cmStrCat(
+      createOptionList, ";", this->Makefile->GetSafeDefinition(createOptVar));
 
     const std::string pchHeader = this->GetPchHeader(config, language);
     const std::string pchFile = this->GetPchFile(config, language);
@@ -3802,9 +3809,16 @@
   if (inserted.second) {
     std::string& useOptionList = inserted.first->second;
 
+    if (this->GetPropertyAsBool("PCH_WARN_INVALID")) {
+      useOptionList = this->Makefile->GetSafeDefinition(
+        cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_INVALID_PCH"));
+    }
+
     const std::string useOptVar =
       cmStrCat("CMAKE_", language, "_COMPILE_OPTIONS_USE_PCH");
-    useOptionList = this->Makefile->GetSafeDefinition(useOptVar);
+
+    useOptionList = cmStrCat(useOptionList, ";",
+                             this->Makefile->GetSafeDefinition(useOptVar));
 
     const std::string pchHeader = this->GetPchHeader(config, language);
     const std::string pchFile = this->GetPchFile(config, language);
diff --git a/Source/cmGetCMakePropertyCommand.cxx b/Source/cmGetCMakePropertyCommand.cxx
index ff4e312..4a9509b 100644
--- a/Source/cmGetCMakePropertyCommand.cxx
+++ b/Source/cmGetCMakePropertyCommand.cxx
@@ -36,12 +36,12 @@
       status.GetMakefile().GetGlobalGenerator()->GetInstallComponents();
     output = cmJoin(*components, ";");
   } else {
-    const char* prop = nullptr;
+    cmProp prop = nullptr;
     if (!args[1].empty()) {
       prop = status.GetMakefile().GetState()->GetGlobalProperty(args[1]);
     }
     if (prop) {
-      output = prop;
+      output = *prop;
     }
   }
 
diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx
index 64438d5..65b3457 100644
--- a/Source/cmGetDirectoryPropertyCommand.cxx
+++ b/Source/cmGetDirectoryPropertyCommand.cxx
@@ -7,7 +7,6 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
-#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 namespace {
@@ -37,14 +36,8 @@
         "DIRECTORY argument provided without subsequent arguments");
       return false;
     }
-    std::string sd = *i;
-    // make sure the start dir is a full path
-    if (!cmSystemTools::FileIsFullPath(sd)) {
-      sd = cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', *i);
-    }
-
-    // The local generators are associated with collapsed paths.
-    sd = cmSystemTools::CollapseFullPath(sd);
+    std::string sd = cmSystemTools::CollapseFullPath(
+      *i, status.GetMakefile().GetCurrentSourceDirectory());
 
     // lookup the makefile from the directory name
     dir = status.GetMakefile().GetGlobalGenerator()->FindMakefile(sd);
diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx
index 947d893..1d8f0a9 100644
--- a/Source/cmGetPropertyCommand.cxx
+++ b/Source/cmGetPropertyCommand.cxx
@@ -241,8 +241,9 @@
 
   // Get the property.
   cmake* cm = status.GetMakefile().GetCMakeInstance();
+  cmProp p = cm->GetState()->GetGlobalProperty(propertyName);
   return StoreResult(infoType, status.GetMakefile(), variable,
-                     cm->GetState()->GetGlobalProperty(propertyName));
+                     p ? p->c_str() : nullptr);
 }
 
 bool HandleDirectoryMode(cmExecutionStatus& status, const std::string& name,
@@ -256,14 +257,8 @@
   if (!name.empty()) {
     // Construct the directory name.  Interpret relative paths with
     // respect to the current directory.
-    std::string dir = name;
-    if (!cmSystemTools::FileIsFullPath(dir)) {
-      dir =
-        cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/', name);
-    }
-
-    // The local generators are associated with collapsed paths.
-    dir = cmSystemTools::CollapseFullPath(dir);
+    std::string dir = cmSystemTools::CollapseFullPath(
+      name, status.GetMakefile().GetCurrentSourceDirectory());
 
     // Lookup the generator.
     mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir);
@@ -393,12 +388,13 @@
     return false;
   }
 
-  const char* value = nullptr;
+  cmProp value = nullptr;
   if (status.GetMakefile().GetState()->GetCacheEntryValue(name)) {
     value = status.GetMakefile().GetState()->GetCacheEntryProperty(
       name, propertyName);
   }
-  StoreResult(infoType, status.GetMakefile(), variable, value);
+  StoreResult(infoType, status.GetMakefile(), variable,
+              value ? value->c_str() : nullptr);
   return true;
 }
 
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 6470ea1..deb722f 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -165,13 +165,15 @@
     outpath = this->GeneratorTarget->GetDirectory(config);
     outpath =
       this->LocalGenerator->MaybeConvertToRelativePath(rootpath, outpath);
-    fout << "    :binDirRelative=\"" << outpath << "\"" << std::endl;
-    fout << "    -o \"" << this->TargetNameReal << "\"" << std::endl;
+    /* clang-format off */
+    fout << "    :binDirRelative=\"" << outpath << "\"\n"
+            "    -o \"" << this->TargetNameReal << "\"\n";
+    /* clang-format on */
   }
 
   // set target object file destination
   outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
-  fout << "    :outputDirRelative=\"" << outpath << "\"" << std::endl;
+  fout << "    :outputDirRelative=\"" << outpath << "\"\n";
 }
 
 void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
@@ -232,7 +234,7 @@
       std::vector<std::string> ghsCompFlags =
         cmSystemTools::ParseArguments(flagsByLangI->second);
       for (const std::string& f : ghsCompFlags) {
-        fout << "    " << f << std::endl;
+        fout << "    " << f << '\n';
       }
     }
   }
@@ -245,7 +247,7 @@
   this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
                                                language);
   for (std::string const& compileDefinition : compileDefinitions) {
-    fout << "    -D" << compileDefinition << std::endl;
+    fout << "    -D" << compileDefinition << '\n';
   }
 }
 
@@ -258,7 +260,7 @@
                                               language, config);
 
   for (std::string const& include : includes) {
-    fout << "    -I\"" << include << "\"" << std::endl;
+    fout << "    -I\"" << include << "\"\n";
   }
 }
 
@@ -287,14 +289,14 @@
   // write out link options
   std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags);
   for (const std::string& l : lopts) {
-    fout << "    " << l << std::endl;
+    fout << "    " << l << '\n';
   }
 
   // write out link search paths
   // must be quoted for paths that contain spaces
   std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath);
   for (const std::string& l : lpath) {
-    fout << "    -L\"" << l << "\"" << std::endl;
+    fout << "    -L\"" << l << "\"\n";
   }
 
   // write out link libs
@@ -305,10 +307,10 @@
     cmSystemTools::ParseArguments(linkLibraries);
   for (const std::string& l : llibs) {
     if (l.compare(0, 2, "-l") == 0) {
-      fout << "    \"" << l << "\"" << std::endl;
+      fout << "    \"" << l << "\"\n";
     } else {
       std::string rl = cmSystemTools::CollapseFullPath(l, cbd);
-      fout << "    -l\"" << rl << "\"" << std::endl;
+      fout << "    -l\"" << rl << "\"\n";
     }
   }
 }
@@ -349,13 +351,12 @@
     this->WriteCustomCommandsHelper(f, ccg);
     f.Close();
     if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
-      fout << "    :" << cmd << "=\"" << fname << "\"" << std::endl;
+      fout << "    :" << cmd << "=\"" << fname << "\"\n";
     } else {
-      fout << fname << std::endl;
-      fout << "    :outputName=\"" << fname << ".rule\"" << std::endl;
+      fout << fname << "\n    :outputName=\"" << fname << ".rule\"\n";
     }
     for (auto& byp : ccg.GetByproducts()) {
-      fout << "    :extraOutputFile=\"" << byp << "\"" << std::endl;
+      fout << "    :extraOutputFile=\"" << byp << "\"\n";
     }
   }
 }
@@ -447,8 +448,7 @@
 
   // push back the custom commands
   for (auto const& c : cmdLines) {
-    fout << c << std::endl;
-    fout << check_error << std::endl;
+    fout << c << '\n' << check_error << '\n';
   }
 }
 
@@ -460,7 +460,7 @@
   if (prop) {
     std::vector<std::string> list = cmExpandedList(prop);
     for (const std::string& p : list) {
-      fout << "    " << propFlag << p << std::endl;
+      fout << "    " << propFlag << p << '\n';
     }
   }
 }
@@ -575,12 +575,12 @@
 
     if (useProjectFile) {
       if (sg.empty()) {
-        *fout << "{comment} Others" << std::endl;
+        *fout << "{comment} Others" << '\n';
       } else {
-        *fout << "{comment} " << sg << std::endl;
+        *fout << "{comment} " << sg << '\n';
       }
     } else if (sg.empty()) {
-      *fout << "{comment} Others" << std::endl;
+      *fout << "{comment} Others\n";
     }
 
     if (sg != "CMake Rules") {
@@ -608,7 +608,7 @@
           compile = false;
         }
 
-        *fout << comment << fname << std::endl;
+        *fout << comment << fname << '\n';
         if (compile) {
           if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
               "bsp" != si->GetExtension()) {
@@ -624,7 +624,7 @@
           std::string objectName = this->GeneratorTarget->GetObjectName(si);
           if (!objectName.empty() &&
               this->GeneratorTarget->HasExplicitObjectName(si)) {
-            *fout << "    -o " << objectName << std::endl;
+            *fout << "    -o " << objectName << '\n';
           }
         }
       }
@@ -691,14 +691,14 @@
    */
   bool specifyExtra = true;
   for (auto& out : ccg.GetOutputs()) {
-    fout << fname << std::endl;
-    fout << "    :outputName=\"" << out << "\"" << std::endl;
+    fout << fname << '\n';
+    fout << "    :outputName=\"" << out << "\"\n";
     if (specifyExtra) {
       for (auto& byp : ccg.GetByproducts()) {
-        fout << "    :extraOutputFile=\"" << byp << "\"" << std::endl;
+        fout << "    :extraOutputFile=\"" << byp << "\"\n";
       }
       for (auto& dep : ccg.GetDepends()) {
-        fout << "    :depends=\"" << dep << "\"" << std::endl;
+        fout << "    :depends=\"" << dep << "\"\n";
       }
       specifyExtra = false;
     }
@@ -713,7 +713,7 @@
     std::string sourceLangProp(rawLangProp);
     std::string const& extension = sourceFile->GetExtension();
     if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
-      fout << "    -dotciscxx" << std::endl;
+      fout << "    -dotciscxx\n";
     }
   }
 }
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 0b9a3e5..6d08369 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -246,11 +246,10 @@
     cmSystemTools::ConvertToUnixSlashes(cnameString);
     cmSystemTools::ConvertToUnixSlashes(pathString);
     if (cnameString != pathString) {
-      const char* cvars =
-        this->GetCMakeInstance()->GetState()->GetGlobalProperty(
-          "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
+      cmProp cvars = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+        "__CMAKE_DELETE_CACHE_CHANGE_VARS_");
       if (cvars) {
-        changeVars += cvars;
+        changeVars += *cvars;
         changeVars += ";";
       }
       changeVars += langComp;
@@ -262,17 +261,16 @@
   }
 }
 
-void cmGlobalGenerator::AddBuildExportSet(
-  std::unique_ptr<cmExportBuildFileGenerator> gen)
+void cmGlobalGenerator::AddBuildExportSet(cmExportBuildFileGenerator* gen)
 {
-  this->BuildExportSets[gen->GetMainExportFileName()] = std::move(gen);
+  this->BuildExportSets[gen->GetMainExportFileName()] = gen;
 }
 
 void cmGlobalGenerator::AddBuildExportExportSet(
-  std::unique_ptr<cmExportBuildFileGenerator> gen)
+  cmExportBuildFileGenerator* gen)
 {
-  this->BuildExportExportSets[gen->GetMainExportFileName()] = gen.get();
-  this->AddBuildExportSet(std::move(gen));
+  this->BuildExportExportSets[gen->GetMainExportFileName()] = gen;
+  this->AddBuildExportSet(gen);
 }
 
 bool cmGlobalGenerator::GenerateImportFile(const std::string& file)
@@ -283,7 +281,7 @@
 
     if (!this->ConfigureDoneCMP0026AndCMP0024) {
       for (const auto& m : this->Makefiles) {
-        m->RemoveExportBuildFileGeneratorCMP0024(it->second.get());
+        m->RemoveExportBuildFileGeneratorCMP0024(it->second);
       }
     }
 
@@ -1317,7 +1315,7 @@
   const std::string& filename) const
 {
   auto const it = this->BuildExportSets.find(filename);
-  return it == this->BuildExportSets.end() ? nullptr : it->second.get();
+  return it == this->BuildExportSets.end() ? nullptr : it->second;
 }
 
 void cmGlobalGenerator::AddCMP0042WarnTarget(const std::string& target)
@@ -1353,9 +1351,9 @@
 void cmGlobalGenerator::ComputeBuildFileGenerators()
 {
   for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
-    std::vector<cmExportBuildFileGenerator*> gens =
+    std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const& gens =
       this->Makefiles[i]->GetExportBuildFileGenerators();
-    for (cmExportBuildFileGenerator* g : gens) {
+    for (std::unique_ptr<cmExportBuildFileGenerator> const& g : gens) {
       g->Compute(this->LocalGenerators[i].get());
     }
   }
@@ -2675,13 +2673,13 @@
   }
 }
 
-const char* cmGlobalGenerator::GetPredefinedTargetsFolder()
+std::string cmGlobalGenerator::GetPredefinedTargetsFolder()
 {
-  const char* prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+  cmProp prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
     "PREDEFINED_TARGETS_FOLDER");
 
   if (prop) {
-    return prop;
+    return *prop;
   }
 
   return "CMakePredefinedTargets";
@@ -2689,13 +2687,13 @@
 
 bool cmGlobalGenerator::UseFolderProperty() const
 {
-  const char* prop =
+  cmProp prop =
     this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS");
 
   // If this property is defined, let the setter turn this on or off...
   //
   if (prop) {
-    return cmIsOn(prop);
+    return cmIsOn(*prop);
   }
 
   // By default, this feature is OFF, since it is not supported in the
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index ba997b2..70e43b5 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -463,13 +463,12 @@
 
   void ProcessEvaluationFiles();
 
-  std::map<std::string, std::unique_ptr<cmExportBuildFileGenerator>>&
-  GetBuildExportSets()
+  std::map<std::string, cmExportBuildFileGenerator*>& GetBuildExportSets()
   {
     return this->BuildExportSets;
   }
-  void AddBuildExportSet(std::unique_ptr<cmExportBuildFileGenerator>);
-  void AddBuildExportExportSet(std::unique_ptr<cmExportBuildFileGenerator>);
+  void AddBuildExportSet(cmExportBuildFileGenerator* gen);
+  void AddBuildExportExportSet(cmExportBuildFileGenerator* gen);
   bool IsExportedTargetsFile(const std::string& filename) const;
   bool GenerateImportFile(const std::string& file);
   cmExportBuildFileGenerator* GetExportedTargetsFile(
@@ -580,8 +579,7 @@
   std::set<std::string> InstallComponents;
   // Sets of named target exports
   cmExportSetMap ExportSets;
-  std::map<std::string, std::unique_ptr<cmExportBuildFileGenerator>>
-    BuildExportSets;
+  std::map<std::string, cmExportBuildFileGenerator*> BuildExportSets;
   std::map<std::string, cmExportBuildFileGenerator*> BuildExportExportSets;
 
   std::map<std::string, std::string> AliasTargets;
@@ -590,7 +588,7 @@
 
   cmGeneratorTarget* FindGeneratorTargetImpl(std::string const& name) const;
 
-  const char* GetPredefinedTargetsFolder();
+  std::string GetPredefinedTargetsFolder();
 
 private:
   using TargetMap = std::unordered_map<std::string, cmTarget*>;
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index 9754fd5..289a035 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -254,14 +254,15 @@
 
 void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout)
 {
-  fout << "#!gbuild" << std::endl;
-  fout << "#" << std::endl
-       << "# CMAKE generated file: DO NOT EDIT!" << std::endl
-       << "# Generated by \"" << GetActualName() << "\""
-       << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
-       << cmVersion::GetMinorVersion() << std::endl
-       << "#" << std::endl
-       << std::endl;
+  /* clang-format off */
+  fout << "#!gbuild\n"
+          "#\n"
+          "# CMAKE generated file: DO NOT EDIT!\n"
+          "# Generated by \"" << GetActualName() << "\""
+          " Generator, CMake Version " << cmVersion::GetMajorVersion() << '.'
+       << cmVersion::GetMinorVersion() << "\n"
+          "#\n\n";
+  /* clang-format on */
 }
 
 void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout)
@@ -269,36 +270,36 @@
   fout << "Commands {\n"
           "  Custom_Rule_Command {\n"
           "    name = \"Custom Rule Command\"\n"
-          "    exec = \"";
+          "    exec = \""
 #ifdef _WIN32
-  fout << "cmd.exe";
+          "cmd.exe"
 #else
-  fout << "/bin/sh";
+          "/bin/sh"
 #endif
-  fout << "\"\n"
+          "\"\n"
           "    options = {\"SpecialOptions\"}\n"
           "  }\n"
-          "}\n";
+          "}\n"
 
-  fout << "\n\n";
-  fout << "FileTypes {\n"
+          "\n\n"
+          "FileTypes {\n"
           "  CmakeRule {\n"
           "    name = \"Custom Rule\"\n"
           "    action = \"&Run\"\n"
-          "    extensions = {\"";
+          "    extensions = {\""
 #ifdef _WIN32
-  fout << "bat";
+          "bat"
 #else
-  fout << "sh";
+          "sh"
 #endif
-  fout << "\"}\n"
+          "\"}\n"
           "    grepable = false\n"
           "    command = \"Custom Rule Command\"\n"
-          "    commandLine = \"$COMMAND ";
+          "    commandLine = \"$COMMAND "
 #ifdef _WIN32
-  fout << "/c";
+          "/c"
 #endif
-  fout << " $INPUTFILE\"\n"
+          " $INPUTFILE\"\n"
           "    progress = \"Processing Custom Rule\"\n"
           "    promoteToFirstPass = true\n"
           "    outputType = \"None\"\n"
@@ -328,13 +329,13 @@
   this->WriteHighLevelDirectives(root, fout);
   GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
 
-  fout << "# Top Level Project File" << std::endl;
+  fout << "# Top Level Project File\n";
 
   // Specify BSP option if supplied by user
   const char* bspName =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
   if (!cmIsOff(bspName)) {
-    fout << "    -bsp " << bspName << std::endl;
+    fout << "    -bsp " << bspName << '\n';
   }
 
   // Specify OS DIR if supplied by user
@@ -349,14 +350,14 @@
     } else {
       fout << osDirOption;
     }
-    fout << "\"" << this->OsDir << "\"" << std::endl;
+    fout << "\"" << this->OsDir << "\"\n";
   }
 }
 
 void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
                                                  std::string& all_target)
 {
-  fout << "CMakeFiles/" << all_target << " [Project]" << std::endl;
+  fout << "CMakeFiles/" << all_target << " [Project]\n";
   // All known targets
   for (cmGeneratorTarget const* target : this->ProjectTargets) {
     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
@@ -367,7 +368,7 @@
       continue;
     }
     fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION
-         << " [Project]" << std::endl;
+         << " [Project]\n";
   }
 }
 
@@ -391,7 +392,7 @@
 
     std::string projFile = dir + projName + FILE_EXTENSION;
     fout << projFile;
-    fout << " " << projType << std::endl;
+    fout << ' ' << projType << '\n';
   } else {
     /* Should never happen */
     std::string message =
@@ -613,14 +614,14 @@
 void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
                                             cmLocalGenerator* root)
 {
-  fout << "macro PROJ_NAME=" << root->GetProjectName() << std::endl;
+  fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n';
   char const* ghsGpjMacros =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
   if (nullptr != ghsGpjMacros) {
     std::vector<std::string> expandedList =
       cmExpandedList(std::string(ghsGpjMacros));
     for (std::string const& arg : expandedList) {
-      fout << "macro " << arg << std::endl;
+      fout << "macro " << arg << '\n';
     }
   }
 }
@@ -643,17 +644,19 @@
     tgt = cmStrCat((a ? a : ""), '_', (p ? p : ""), ".tgt");
   }
 
-  fout << "primaryTarget=" << tgt << std::endl;
-  fout << "customization=" << root->GetBinaryDirectory()
-       << "/CMakeFiles/custom_rule.bod" << std::endl;
-  fout << "customization=" << root->GetBinaryDirectory()
-       << "/CMakeFiles/custom_target.bod" << std::endl;
+  /* clang-format off */
+  fout << "primaryTarget=" << tgt << "\n"
+          "customization=" << root->GetBinaryDirectory()
+       << "/CMakeFiles/custom_rule.bod\n"
+          "customization=" << root->GetBinaryDirectory()
+       << "/CMakeFiles/custom_target.bod" << '\n';
+  /* clang-format on */
 
   char const* const customization =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
   if (nullptr != customization && strlen(customization) > 0) {
     fout << "customization="
-         << cmGlobalGhsMultiGenerator::TrimQuotes(customization) << std::endl;
+         << cmGlobalGhsMultiGenerator::TrimQuotes(customization) << '\n';
     this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
   }
 }
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index d58113c..062f8e9 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1009,9 +1009,9 @@
     // Get a stream where to generate things.
     this->CompileCommandsStream =
       cm::make_unique<cmGeneratedFileStream>(buildFilePath);
-    *this->CompileCommandsStream << "[";
+    *this->CompileCommandsStream << "[\n";
   } else {
-    *this->CompileCommandsStream << "," << std::endl;
+    *this->CompileCommandsStream << ",\n";
   }
 
   std::string sourceFileName = sourceFile;
@@ -1021,7 +1021,7 @@
   }
 
   /* clang-format off */
-  *this->CompileCommandsStream << "\n{\n"
+  *this->CompileCommandsStream << "{\n"
      << R"(  "directory": ")"
      << cmGlobalGenerator::EscapeJSON(buildFileDir) << "\",\n"
      << R"(  "command": ")"
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 7daca74..582877f 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -159,7 +159,7 @@
   this->WriteMainCMakefile();
 
   if (this->CommandDatabase) {
-    *this->CommandDatabase << std::endl << "]";
+    *this->CommandDatabase << "\n]";
     this->CommandDatabase.reset();
   }
 }
@@ -174,21 +174,20 @@
       "/compile_commands.json";
     this->CommandDatabase =
       cm::make_unique<cmGeneratedFileStream>(commandDatabaseName);
-    *this->CommandDatabase << "[" << std::endl;
+    *this->CommandDatabase << "[\n";
   } else {
-    *this->CommandDatabase << "," << std::endl;
+    *this->CommandDatabase << ",\n";
   }
-  *this->CommandDatabase << "{" << std::endl
+  *this->CommandDatabase << "{\n"
                          << R"(  "directory": ")"
                          << cmGlobalGenerator::EscapeJSON(workingDirectory)
-                         << "\"," << std::endl
+                         << "\",\n"
                          << R"(  "command": ")"
                          << cmGlobalGenerator::EscapeJSON(compileCommand)
-                         << "\"," << std::endl
+                         << "\",\n"
                          << R"(  "file": ")"
-                         << cmGlobalGenerator::EscapeJSON(sourceFile) << "\""
-                         << std::endl
-                         << "}";
+                         << cmGlobalGenerator::EscapeJSON(sourceFile)
+                         << "\"\n}";
 }
 
 void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
@@ -674,10 +673,10 @@
       }
 
       bool targetMessages = true;
-      if (const char* tgtMsg =
+      if (cmProp tgtMsg =
             this->GetCMakeInstance()->GetState()->GetGlobalProperty(
               "TARGET_MESSAGES")) {
-        targetMessages = cmIsOn(tgtMsg);
+        targetMessages = cmIsOn(*tgtMsg);
       }
 
       if (targetMessages) {
@@ -697,9 +696,8 @@
         std::ostringstream progCmd;
         progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
         // # in target
-        progCmd << lg.ConvertToOutputFormat(
-          cmSystemTools::CollapseFullPath(progress.Dir),
-          cmOutputConverter::SHELL);
+        progCmd << lg.ConvertToOutputFormat(progress.Dir,
+                                            cmOutputConverter::SHELL);
         //
         std::set<cmGeneratorTarget const*> emitted;
         progCmd << " "
@@ -711,9 +709,8 @@
       {
         std::ostringstream progCmd;
         progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
-        progCmd << lg.ConvertToOutputFormat(
-          cmSystemTools::CollapseFullPath(progress.Dir),
-          cmOutputConverter::SHELL);
+        progCmd << lg.ConvertToOutputFormat(progress.Dir,
+                                            cmOutputConverter::SHELL);
         progCmd << " 0";
         commands.push_back(progCmd.str());
       }
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index ccb6c50..5166de6 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -19,6 +19,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
 #include "cmVersion.h"
 #include "cmVisualStudioSlnData.h"
 #include "cmVisualStudioSlnParser.h"
@@ -313,7 +314,7 @@
       version.clear();
     }
 
-    if (version.find(this->GetPlatformToolsetString()) != 0) {
+    if (!cmHasPrefix(version, this->GetPlatformToolsetString())) {
       std::ostringstream e;
       /* clang-format off */
       e <<
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 43d31bc..9a9900a 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -505,13 +505,13 @@
   const std::vector<std::string> propKeys =
     root->GetMakefile()->GetPropertyKeys();
   for (std::string const& it : propKeys) {
-    if (it.find("VS_GLOBAL_SECTION_") == 0) {
+    if (cmHasLiteralPrefix(it, "VS_GLOBAL_SECTION_")) {
       std::string sectionType;
       std::string name = it.substr(18);
-      if (name.find("PRE_") == 0) {
+      if (cmHasLiteralPrefix(name, "PRE_")) {
         name = name.substr(4);
         sectionType = "preSolution";
-      } else if (name.find("POST_") == 0) {
+      } else if (cmHasLiteralPrefix(name, "POST_")) {
         name = name.substr(5);
         sectionType = "postSolution";
       } else
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 9db4817..1c1aaad 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -34,6 +34,7 @@
 #include "cmSourceGroup.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmXCode21Object.h"
@@ -2407,7 +2408,7 @@
   // Convert "XCODE_ATTRIBUTE_*" properties directly.
   {
     for (auto const& prop : gtgt->GetPropertyKeys()) {
-      if (prop.find("XCODE_ATTRIBUTE_") == 0) {
+      if (cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) {
         std::string attribute = prop.substr(16);
         this->FilterConfigurationAttribute(configName, attribute);
         if (!attribute.empty()) {
@@ -3143,7 +3144,7 @@
     // Put this last so it can override existing settings
     // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly.
     for (const auto& var : this->CurrentMakefile->GetDefinitions()) {
-      if (var.find("CMAKE_XCODE_ATTRIBUTE_") == 0) {
+      if (cmHasLiteralPrefix(var, "CMAKE_XCODE_ATTRIBUTE_")) {
         std::string attribute = var.substr(22);
         this->FilterConfigurationAttribute(config.first, attribute);
         if (!attribute.empty()) {
@@ -3695,15 +3696,14 @@
 
 bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const
 {
-  const char* epnValue =
-    this->GetCMakeInstance()->GetState()->GetGlobalProperty(
-      "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME");
+  cmProp epnValue = this->GetCMakeInstance()->GetState()->GetGlobalProperty(
+    "XCODE_EMIT_EFFECTIVE_PLATFORM_NAME");
 
   if (!epnValue) {
     return mf->PlatformIsAppleEmbedded();
   }
 
-  return cmIsOn(epnValue);
+  return cmIsOn(*epnValue);
 }
 
 bool cmGlobalXCodeGenerator::ShouldStripResourcePath(cmMakefile*) const
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index 1b77678..0fcda4e 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -298,13 +298,13 @@
                                    const std::string& name)
 {
   auto const escapedGraphName = EscapeForDotFile(name);
-  fs << "digraph \"" << escapedGraphName << "\" {" << std::endl;
-  fs << this->GraphHeader << std::endl;
+  fs << "digraph \"" << escapedGraphName << "\" {\n"
+     << this->GraphHeader << '\n';
 }
 
 void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& fs)
 {
-  fs << "}" << std::endl;
+  fs << "}\n";
 }
 
 void cmGraphVizWriter::WriteLegend(cmGeneratedFileStream& fs)
@@ -312,52 +312,46 @@
   // Note that the subgraph name must start with "cluster", as done here, to
   // make Graphviz layout engines do the right thing and keep the nodes
   // together.
-  fs << "subgraph clusterLegend {" << std::endl;
-  fs << "  label = \"Legend\";" << std::endl;
-  // Set the color of the box surrounding the legend.
-  fs << "  color = black;" << std::endl;
-  // We use invisible edges just to enforce the layout.
-  fs << "  edge [ style = invis ];" << std::endl;
-
-  // Nodes.
-  fs << "  legendNode0 [ label = \"Executable\", shape = "
-     << GRAPHVIZ_NODE_SHAPE_EXECUTABLE << " ];" << std::endl;
-
-  fs << "  legendNode1 [ label = \"Static Library\", shape = "
-     << GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC << " ];" << std::endl;
-  fs << "  legendNode2 [ label = \"Shared Library\", shape = "
-     << GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED << " ];" << std::endl;
-  fs << "  legendNode3 [ label = \"Module Library\", shape = "
-     << GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE << " ];" << std::endl;
-
-  fs << "  legendNode4 [ label = \"Interface Library\", shape = "
-     << GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE << " ];" << std::endl;
-  fs << "  legendNode5 [ label = \"Object Library\", shape = "
-     << GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT << " ];" << std::endl;
-  fs << "  legendNode6 [ label = \"Unknown Library\", shape = "
-     << GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN << " ];" << std::endl;
-
-  fs << "  legendNode7 [ label = \"Custom Target\", shape = "
-     << GRAPHVIZ_NODE_SHAPE_UTILITY << " ];" << std::endl;
-
-  // Edges.
-  // Some of those are dummy (invisible) edges to enforce a layout.
-  fs << "  legendNode0 -> legendNode1 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
-     << " ];" << std::endl;
-  fs << "  legendNode0 -> legendNode2 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
-     << " ];" << std::endl;
-  fs << "  legendNode0 -> legendNode3;" << std::endl;
-
-  fs << "  legendNode1 -> legendNode4 [ label = \"Interface\", style = "
-     << GRAPHVIZ_EDGE_STYLE_INTERFACE << " ];" << std::endl;
-  fs << "  legendNode2 -> legendNode5 [ label = \"Private\", style = "
-     << GRAPHVIZ_EDGE_STYLE_PRIVATE << " ];" << std::endl;
-  fs << "  legendNode3 -> legendNode6 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
-     << " ];" << std::endl;
-
-  fs << "  legendNode0 -> legendNode7;" << std::endl;
-
-  fs << "}" << std::endl;
+  /* clang-format off */
+  fs << "subgraph clusterLegend {\n"
+        "  label = \"Legend\";\n"
+        // Set the color of the box surrounding the legend.
+        "  color = black;\n"
+        // We use invisible edges just to enforce the layout.
+        "  edge [ style = invis ];\n"
+        // Nodes.
+        "  legendNode0 [ label = \"Executable\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_EXECUTABLE << " ];\n"
+        "  legendNode1 [ label = \"Static Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC << " ];\n"
+        "  legendNode2 [ label = \"Shared Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED << " ];\n"
+        "  legendNode3 [ label = \"Module Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE << " ];\n"
+        "  legendNode4 [ label = \"Interface Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE << " ];\n"
+        "  legendNode5 [ label = \"Object Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT << " ];\n"
+        "  legendNode6 [ label = \"Unknown Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN << " ];\n"
+        "  legendNode7 [ label = \"Custom Target\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_UTILITY << " ];\n"
+        // Edges.
+        // Some of those are dummy (invisible) edges to enforce a layout.
+        "  legendNode0 -> legendNode1 [ style = "
+     << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n"
+        "  legendNode0 -> legendNode2 [ style = "
+     << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n"
+        "  legendNode0 -> legendNode3;\n"
+        "  legendNode1 -> legendNode4 [ label = \"Interface\", style = "
+     << GRAPHVIZ_EDGE_STYLE_INTERFACE << " ];\n"
+        "  legendNode2 -> legendNode5 [ label = \"Private\", style = "
+     << GRAPHVIZ_EDGE_STYLE_PRIVATE << " ];\n"
+        "  legendNode3 -> legendNode6 [ style = "
+     << GRAPHVIZ_EDGE_STYLE_PUBLIC << " ];\n"
+        "  legendNode0 -> legendNode7;\n"
+        "}\n";
+  /* clang-format off */
 }
 
 void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs,
@@ -370,7 +364,7 @@
   auto const escapedLabel = EscapeForDotFile(itemNameWithAliases);
 
   fs << "    \"" << nodeName << "\" [ label = \"" << escapedLabel
-     << "\", shape = " << getShapeForTarget(item) << " ];" << std::endl;
+     << "\", shape = " << getShapeForTarget(item) << " ];\n";
 }
 
 void cmGraphVizWriter::WriteConnection(cmGeneratedFileStream& fs,
@@ -382,11 +376,9 @@
   auto const& dependeeName = dependee.AsStr();
 
   fs << "    \"" << this->NodeNames[dependerName] << "\" -> \""
-     << this->NodeNames[dependeeName] << "\" ";
-
-  fs << edgeStyle;
-
-  fs << " // " << dependerName << " -> " << dependeeName << std::endl;
+     << this->NodeNames[dependeeName] << "\" "
+     << edgeStyle
+     << " // " << dependerName << " -> " << dependeeName << '\n';
 }
 
 bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item)
@@ -402,9 +394,9 @@
   }
 
   if (item.Target->GetType() == cmStateEnums::UTILITY) {
-    if ((itemName.find("Nightly") == 0) ||
-        (itemName.find("Continuous") == 0) ||
-        (itemName.find("Experimental") == 0)) {
+    if (cmHasLiteralPrefix(itemName, "Nightly") ||
+        cmHasLiteralPrefix(itemName, "Continuous") ||
+        cmHasLiteralPrefix(itemName, "Experimental")) {
       return true;
     }
   }
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
index dd36386..9ecf378 100644
--- a/Source/cmJsonObjects.cxx
+++ b/Source/cmJsonObjects.cxx
@@ -90,7 +90,8 @@
 
       const std::string startOfFile = lf.substr(0, cmakeRootDir.size());
       const bool isInternal = (startOfFile == cmakeRootDir);
-      const bool isTemporary = !isInternal && (lf.find(buildDir + '/') == 0);
+      const bool isTemporary =
+        !isInternal && (cmHasPrefix(lf, buildDir + '/'));
 
       std::string toAdd = lf;
       if (!sourceDir.empty()) {
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
index 92258e2..5790e16 100644
--- a/Source/cmLoadCommandCommand.cxx
+++ b/Source/cmLoadCommandCommand.cxx
@@ -1,5 +1,15 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#if !defined(_WIN32) && !defined(__sun)
+// POSIX APIs are needed
+#  define _POSIX_C_SOURCE 200809L
+#endif
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+// For isascii
+#  define _XOPEN_SOURCE 700
+#endif
+
 #include "cmLoadCommandCommand.h"
 
 #include <csignal>
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index a7799b6..e908180 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -288,21 +288,23 @@
   cmGeneratedFileStream fout(file);
   fout.SetCopyIfDifferent(true);
 
-  fout << "# CMake generated Testfile for " << std::endl
-       << "# Source directory: "
-       << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
-       << "# Build directory: "
-       << this->StateSnapshot.GetDirectory().GetCurrentBinary() << std::endl
-       << "# " << std::endl
-       << "# This file includes the relevant testing commands "
-       << "required for " << std::endl
-       << "# testing this directory and lists subdirectories to "
-       << "be tested as well." << std::endl;
+  fout << "# CMake generated Testfile for \n"
+          "# Source directory: "
+       << this->StateSnapshot.GetDirectory().GetCurrentSource()
+       << "\n"
+          "# Build directory: "
+       << this->StateSnapshot.GetDirectory().GetCurrentBinary()
+       << "\n"
+          "# \n"
+          "# This file includes the relevant testing commands "
+          "required for \n"
+          "# testing this directory and lists subdirectories to "
+          "be tested as well.\n";
 
   const char* testIncludeFile =
     this->Makefile->GetProperty("TEST_INCLUDE_FILE");
   if (testIncludeFile) {
-    fout << "include(\"" << testIncludeFile << "\")" << std::endl;
+    fout << "include(\"" << testIncludeFile << "\")\n";
   }
 
   const char* testIncludeFiles =
@@ -310,7 +312,7 @@
   if (testIncludeFiles) {
     std::vector<std::string> includesList = cmExpandedList(testIncludeFiles);
     for (std::string const& i : includesList) {
-      fout << "include(\"" << i << "\")" << std::endl;
+      fout << "include(\"" << i << "\")\n";
     }
   }
 
@@ -327,7 +329,7 @@
     std::string outP = i.GetDirectory().GetCurrentBinary();
     outP = this->MaybeConvertToRelativePath(parentBinDir, outP);
     outP = cmOutputConverter::EscapeForCMake(outP);
-    fout << "subdirs(" << outP << ")" << std::endl;
+    fout << "subdirs(" << outP << ")\n";
   }
 
   // Add directory labels property
@@ -346,7 +348,7 @@
     if (directoryLabels) {
       fout << cmOutputConverter::EscapeForCMake(directoryLabels);
     }
-    fout << ")" << std::endl;
+    fout << ")\n";
   }
 }
 
@@ -467,16 +469,17 @@
   fout.SetCopyIfDifferent(true);
 
   // Write the header.
+  /* clang-format off */
   fout << "# Install script for directory: "
-       << this->StateSnapshot.GetDirectory().GetCurrentSource() << std::endl
-       << std::endl;
-  fout << "# Set the install prefix" << std::endl
-       << "if(NOT DEFINED CMAKE_INSTALL_PREFIX)" << std::endl
-       << "  set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")" << std::endl
-       << "endif()" << std::endl
+       << this->StateSnapshot.GetDirectory().GetCurrentSource()
+       << "\n\n"
+          "# Set the install prefix\n"
+          "if(NOT DEFINED CMAKE_INSTALL_PREFIX)\n"
+          "  set(CMAKE_INSTALL_PREFIX \"" << prefix << "\")\n"
+          "endif()\n"
        << R"(string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX )"
-       << "\"${CMAKE_INSTALL_PREFIX}\")" << std::endl
-       << std::endl;
+       << "\"${CMAKE_INSTALL_PREFIX}\")\n\n";
+  /* clang-format on */
 
   // Write support code for generating per-configuration install rules.
   /* clang-format off */
@@ -591,8 +594,7 @@
           if (!c.GetDirectory().GetPropertyAsBool("EXCLUDE_FROM_ALL")) {
             std::string odir = c.GetDirectory().GetCurrentBinary();
             cmSystemTools::ConvertToUnixSlashes(odir);
-            fout << "  include(\"" << odir << "/cmake_install.cmake\")"
-                 << std::endl;
+            fout << "  include(\"" << odir << "/cmake_install.cmake\")\n";
           }
         }
         fout << "\n";
@@ -877,7 +879,7 @@
   if ((sep[0] != ' ') && !flags.empty() && flags.back() == sep[0]) {
     flags.back() = ' ';
   }
-  return flags;
+  return cmTrimWhitespace(flags);
 }
 
 void cmLocalGenerator::AddCompileOptions(std::string& flags,
@@ -949,8 +951,7 @@
         << "\".  "
            "This is not permitted. The COMPILE_FEATURES may not both depend "
            "on "
-           "and be depended on by the link implementation."
-        << std::endl;
+           "and be depended on by the link implementation.\n";
       this->IssueMessage(MessageType::FATAL_ERROR, e.str());
       return;
     }
@@ -1390,8 +1391,8 @@
           for (cmSourceFile* sf : sources) {
             if (sf->GetExtension() == "def") {
               sharedLibFlags += defFlag;
-              sharedLibFlags += this->ConvertToOutputFormat(
-                cmSystemTools::CollapseFullPath(sf->ResolveFullPath()), SHELL);
+              sharedLibFlags +=
+                this->ConvertToOutputFormat(sf->ResolveFullPath(), SHELL);
               sharedLibFlags += " ";
             }
           }
@@ -2396,7 +2397,9 @@
 void cmLocalGenerator::AppendFlags(std::string& flags,
                                    const std::string& newFlags) const
 {
-  if (!newFlags.empty()) {
+  bool allSpaces = std::all_of(newFlags.begin(), newFlags.end(), cmIsSpace);
+
+  if (!newFlags.empty() && !allSpaces) {
     if (!flags.empty()) {
       flags += " ";
     }
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index be1dd0d..e62371d 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -144,8 +144,9 @@
   bool forceFullPaths)
 {
   if (forceFullPaths) {
-    return this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(path),
-                                       format);
+    return this->ConvertToOutputFormat(
+      cmSystemTools::CollapseFullPath(path, this->GetCurrentBinaryDirectory()),
+      format);
   }
   return this->ConvertToOutputFormat(
     this->MaybeConvertToRelativePath(this->GetBinaryDirectory(), path),
@@ -206,9 +207,8 @@
 void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os)
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
-  os << "# Project: " << this->GetProjectName() << std::endl
-     << "# Configurations: " << cmJoin(this->GetConfigNames(), ", ")
-     << std::endl;
+  os << "# Project: " << this->GetProjectName() << '\n'
+     << "# Configurations: " << cmJoin(this->GetConfigNames(), ", ") << '\n';
   cmGlobalNinjaGenerator::WriteDivider(os);
 }
 
@@ -235,8 +235,7 @@
 
   cmGlobalNinjaGenerator::WriteComment(
     os, "Minimal version of Ninja required by this file");
-  os << "ninja_required_version = " << requiredVersion << std::endl
-     << std::endl;
+  os << "ninja_required_version = " << requiredVersion << "\n\n";
 }
 
 void cmLocalNinjaGenerator::WriteNinjaConfigurationVariable(
@@ -251,23 +250,22 @@
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
 
-  const char* jobpools =
+  cmProp jobpools =
     this->GetCMakeInstance()->GetState()->GetGlobalProperty("JOB_POOLS");
   if (!jobpools) {
-    jobpools = this->GetMakefile()->GetDefinition("CMAKE_JOB_POOLS");
+    jobpools = this->GetMakefile()->GetDef("CMAKE_JOB_POOLS");
   }
   if (jobpools) {
     cmGlobalNinjaGenerator::WriteComment(
       os, "Pools defined by global property JOB_POOLS");
-    std::vector<std::string> pools = cmExpandedList(jobpools);
+    std::vector<std::string> pools = cmExpandedList(*jobpools);
     for (std::string const& pool : pools) {
       const std::string::size_type eq = pool.find('=');
       unsigned int jobs;
       if (eq != std::string::npos &&
           sscanf(pool.c_str() + eq, "=%u", &jobs) == 1) {
-        os << "pool " << pool.substr(0, eq) << std::endl;
-        os << "  depth = " << jobs << std::endl;
-        os << std::endl;
+        os << "pool " << pool.substr(0, eq) << "\n  depth = " << jobs
+           << "\n\n";
       } else {
         cmSystemTools::Error("Invalid pool defined by property 'JOB_POOLS': " +
                              pool);
@@ -279,8 +277,7 @@
 void cmLocalNinjaGenerator::WriteNinjaFilesInclusionConfig(std::ostream& os)
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
-  os << "# Include auxiliary files.\n"
-     << "\n";
+  os << "# Include auxiliary files.\n\n";
   cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator();
   std::string const ninjaCommonFile =
     ng->NinjaOutputPath(cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE);
@@ -293,8 +290,7 @@
 void cmLocalNinjaGenerator::WriteNinjaFilesInclusionCommon(std::ostream& os)
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
-  os << "# Include auxiliary files.\n"
-     << "\n";
+  os << "# Include auxiliary files.\n\n";
   cmGlobalNinjaGenerator* ng = this->GetGlobalNinjaGenerator();
   std::string const ninjaRulesFile =
     ng->NinjaOutputPath(cmGlobalNinjaGenerator::NINJA_RULES_FILE);
@@ -307,14 +303,14 @@
 void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os)
 {
   cmGlobalNinjaGenerator::WriteDivider(os);
-  os << "# Write statements declared in CMakeLists.txt:" << std::endl
+  os << "# Write statements declared in CMakeLists.txt:\n"
      << "# " << this->Makefile->GetDefinition("CMAKE_CURRENT_LIST_FILE")
-     << std::endl;
+     << '\n';
   if (this->IsRootMakefile()) {
-    os << "# Which is the root file." << std::endl;
+    os << "# Which is the root file.\n";
   }
   cmGlobalNinjaGenerator::WriteDivider(os);
-  os << std::endl;
+  os << '\n';
 }
 
 void cmLocalNinjaGenerator::AppendTargetOutputs(cmGeneratorTarget* target,
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 63c6680..593a6d9 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -623,8 +623,7 @@
     this->MaybeConvertWatcomShellCommand(cmSystemTools::GetCMakeCommand());
   if (cmakeShellCommand.empty()) {
     cmakeShellCommand = this->ConvertToOutputFormat(
-      cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()),
-      cmOutputConverter::SHELL);
+      cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
   }
 
   /* clang-format off */
@@ -648,16 +647,14 @@
     << "# The top-level source directory on which CMake was run.\n"
     << "CMAKE_SOURCE_DIR = "
     << this->ConvertToOutputFormat(
-      cmSystemTools::CollapseFullPath(this->GetSourceDirectory()),
-                     cmOutputConverter::SHELL)
+      this->GetSourceDirectory(), cmOutputConverter::SHELL)
     << "\n"
     << "\n";
   makefileStream
     << "# The top-level build directory on which CMake was run.\n"
     << "CMAKE_BINARY_DIR = "
     << this->ConvertToOutputFormat(
-      cmSystemTools::CollapseFullPath(this->GetBinaryDirectory()),
-                     cmOutputConverter::SHELL)
+      this->GetBinaryDirectory(), cmOutputConverter::SHELL)
     << "\n"
     << "\n";
   /* clang-format on */
@@ -728,6 +725,10 @@
       ;
     /* clang-format on */
   } else {
+    makefileStream << "# Command-line flag to silence nested $(MAKE).\n"
+                      "$(VERBOSE)MAKESILENT = -s\n"
+                      "\n";
+
     // Write special target to silence make output.  This must be after
     // the default target in case VERBOSE is set (which changes the
     // name).  The setting of CMAKE_VERBOSE_MAKEFILE to ON will cause a
@@ -974,7 +975,8 @@
         // Expand rule variables referenced in the given launcher command.
         cmRulePlaceholderExpander::RuleVariables vars;
         vars.CMTargetName = target->GetName().c_str();
-        vars.CMTargetType = cmState::GetTargetTypeName(target->GetType());
+        vars.CMTargetType =
+          cmState::GetTargetTypeName(target->GetType()).c_str();
         std::string output;
         const std::vector<std::string>& outputs = ccg.GetOutputs();
         if (!outputs.empty()) {
@@ -1053,10 +1055,9 @@
     cleanfile += filename;
   }
   cleanfile += ".cmake";
-  std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
-  cmsys::ofstream fout(cleanfilePath.c_str());
+  cmsys::ofstream fout(cleanfile.c_str());
   if (!fout) {
-    cmSystemTools::Error("Could not create " + cleanfilePath);
+    cmSystemTools::Error("Could not create " + cleanfile);
   }
   if (!files.empty()) {
     fout << "file(REMOVE_RECURSE\n";
@@ -1116,10 +1117,9 @@
     cmStrCat(currentBinaryDir, "/CMakeFiles/cmake_directory_clean.cmake");
   // Write clean script
   {
-    std::string cleanfilePath = cmSystemTools::CollapseFullPath(cleanfile);
-    cmsys::ofstream fout(cleanfilePath.c_str());
+    cmsys::ofstream fout(cleanfile.c_str());
     if (!fout) {
-      cmSystemTools::Error("Could not create " + cleanfilePath);
+      cmSystemTools::Error("Could not create " + cleanfile);
       return;
     }
     fout << "file(REMOVE_RECURSE\n";
@@ -1190,9 +1190,8 @@
             color_name);
           if (progress) {
             cmd += "--progress-dir=";
-            cmd += this->ConvertToOutputFormat(
-              cmSystemTools::CollapseFullPath(progress->Dir),
-              cmOutputConverter::SHELL);
+            cmd += this->ConvertToOutputFormat(progress->Dir,
+                                               cmOutputConverter::SHELL);
             cmd += " ";
             cmd += "--progress-num=";
             cmd += progress->Arg;
@@ -1327,10 +1326,9 @@
     int result;
     if (!ftc->Compare(internalDependFile, tgtInfo, &result) || result < 0) {
       if (verbose) {
-        std::ostringstream msg;
-        msg << "Dependee \"" << tgtInfo << "\" is newer than depender \""
-            << internalDependFile << "\"." << std::endl;
-        cmSystemTools::Stdout(msg.str());
+        cmSystemTools::Stdout(cmStrCat("Dependee \"", tgtInfo,
+                                       "\" is newer than depender \"",
+                                       internalDependFile, "\".\n"));
       }
       needRescanDependInfo = true;
     }
@@ -1347,10 +1345,9 @@
     if (!ftc->Compare(internalDependFile, dirInfoFile, &result) ||
         result < 0) {
       if (verbose) {
-        std::ostringstream msg;
-        msg << "Dependee \"" << dirInfoFile << "\" is newer than depender \""
-            << internalDependFile << "\"." << std::endl;
-        cmSystemTools::Stdout(msg.str());
+        cmSystemTools::Stdout(cmStrCat("Dependee \"", dirInfoFile,
+                                       "\" is newer than depender \"",
+                                       internalDependFile, "\".\n"));
       }
       needRescanDirInfo = true;
     }
@@ -1516,11 +1513,9 @@
     if (cmSystemTools::FileExists(dependee) &&
         !cmSystemTools::FileExists(depender)) {
       if (verbose) {
-        std::ostringstream msg;
-        msg << "Deleting primary custom command output \"" << dependee
-            << "\" because another output \"" << depender
-            << "\" does not exist." << std::endl;
-        cmSystemTools::Stdout(msg.str());
+        cmSystemTools::Stdout(cmStrCat(
+          "Deleting primary custom command output \"", dependee,
+          "\" because another output \"", depender, "\" does not exist.\n"));
       }
       cmSystemTools::RemoveFile(dependee);
     }
@@ -1632,15 +1627,14 @@
   {
     std::ostringstream progCmd;
     progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
-    progCmd << this->ConvertToOutputFormat(
-      cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL);
+    progCmd << this->ConvertToOutputFormat(progressDir,
+                                           cmOutputConverter::SHELL);
 
     std::string progressFile = "/CMakeFiles/progress.marks";
     std::string progressFileNameFull = this->ConvertToFullPath(progressFile);
     progCmd << " "
-            << this->ConvertToOutputFormat(
-                 cmSystemTools::CollapseFullPath(progressFileNameFull),
-                 cmOutputConverter::SHELL);
+            << this->ConvertToOutputFormat(progressFileNameFull,
+                                           cmOutputConverter::SHELL);
     commands.push_back(progCmd.str());
   }
   std::string mf2Dir = "CMakeFiles/Makefile2";
@@ -1650,8 +1644,8 @@
   {
     std::ostringstream progCmd;
     progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
-    progCmd << this->ConvertToOutputFormat(
-      cmSystemTools::CollapseFullPath(progressDir), cmOutputConverter::SHELL);
+    progCmd << this->ConvertToOutputFormat(progressDir,
+                                           cmOutputConverter::SHELL);
     progCmd << " 0";
     commands.push_back(progCmd.str());
   }
@@ -1784,7 +1778,7 @@
                             const std::string& testDir)
   {
     // First check if the test directory "starts with" the base directory:
-    if (testDir.find(baseDir) != 0) {
+    if (!cmHasPrefix(testDir, baseDir)) {
       return false;
     }
     // If it does, then check that it's either the same string, or that the
@@ -1925,7 +1919,7 @@
 {
   // Call make on the given file.
   std::string cmd = cmStrCat(
-    "$(MAKE) -f ",
+    "$(MAKE) $(MAKESILENT) -f ",
     this->ConvertToOutputFormat(makefile, cmOutputConverter::SHELL), ' ');
 
   cmGlobalUnixMakefileGenerator3* gg =
@@ -1968,7 +1962,7 @@
 void cmLocalUnixMakefileGenerator3::WriteDivider(std::ostream& os)
 {
   os << "#======================================"
-     << "=======================================\n";
+        "=======================================\n";
 }
 
 void cmLocalUnixMakefileGenerator3::WriteCMakeArgument(std::ostream& os,
@@ -1976,7 +1970,7 @@
 {
   // Write the given string to the stream with escaping to get it back
   // into CMake through the lexical scanner.
-  os << "\"";
+  os << '"';
   for (char c : s) {
     if (c == '\\') {
       os << "\\\\";
@@ -1986,7 +1980,7 @@
       os << c;
     }
   }
-  os << "\"";
+  os << '"';
 }
 
 std::string cmLocalUnixMakefileGenerator3::ConvertToQuotedOutputPath(
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 74219b5..0c1f0cc 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -20,6 +20,7 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmXMLParser.h"
 #include "cmake.h"
@@ -225,7 +226,6 @@
 
   std::string makefileIn =
     cmStrCat(this->GetCurrentSourceDirectory(), "/CMakeLists.txt");
-  makefileIn = cmSystemTools::CollapseFullPath(makefileIn);
   if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
     if (file->GetCustomCommand()) {
       return file;
@@ -256,8 +256,7 @@
                               "--check-stamp-file", stampName });
   std::string comment = cmStrCat("Building Custom Rule ", makefileIn);
   const char* no_working_directory = nullptr;
-  std::string fullpathStampName = cmSystemTools::CollapseFullPath(stampName);
-  this->AddCustomCommandToOutput(fullpathStampName, listFiles, makefileIn,
+  this->AddCustomCommandToOutput(stampName, listFiles, makefileIn,
                                  commandLines, comment.c_str(),
                                  no_working_directory, true, false);
   if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) {
@@ -2008,7 +2007,7 @@
   fout << "\t<Globals>\n";
 
   for (std::string const& key : target->GetPropertyKeys()) {
-    if (key.find("VS_GLOBAL_") == 0) {
+    if (cmHasLiteralPrefix(key, "VS_GLOBAL_")) {
       std::string name = key.substr(10);
       if (!name.empty()) {
         /* clang-format off */
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
index 8d50898..7267976 100644
--- a/Source/cmLocalVisualStudioGenerator.cxx
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -154,8 +154,7 @@
     script += newline;
     newline = newline_text;
     script += "cd ";
-    script += this->ConvertToOutputFormat(
-      cmSystemTools::CollapseFullPath(workingDirectory), SHELL);
+    script += this->ConvertToOutputFormat(workingDirectory, SHELL);
     script += check_error;
 
     // Change the working drive.
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 831b1fb..2487f4d 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -32,6 +32,7 @@
 #include "cmCustomCommandLines.h"
 #include "cmExecutionStatus.h"
 #include "cmExpandedCommandArgument.h" // IWYU pragma: keep
+#include "cmExportBuildFileGenerator.h"
 #include "cmFileLockPool.h"
 #include "cmFunctionBlocker.h"
 #include "cmGeneratedFileStream.h"
@@ -813,7 +814,7 @@
   return this->EvaluationFiles;
 }
 
-std::vector<cmExportBuildFileGenerator*>
+std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const&
 cmMakefile::GetExportBuildFileGenerators() const
 {
   return this->ExportBuildFileGenerators;
@@ -822,16 +823,21 @@
 void cmMakefile::RemoveExportBuildFileGeneratorCMP0024(
   cmExportBuildFileGenerator* gen)
 {
-  auto it = std::find(this->ExportBuildFileGenerators.begin(),
-                      this->ExportBuildFileGenerators.end(), gen);
+  auto it =
+    std::find_if(this->ExportBuildFileGenerators.begin(),
+                 this->ExportBuildFileGenerators.end(),
+                 [gen](std::unique_ptr<cmExportBuildFileGenerator> const& p) {
+                   return p.get() == gen;
+                 });
   if (it != this->ExportBuildFileGenerators.end()) {
     this->ExportBuildFileGenerators.erase(it);
   }
 }
 
-void cmMakefile::AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen)
+void cmMakefile::AddExportBuildFileGenerator(
+  std::unique_ptr<cmExportBuildFileGenerator> gen)
 {
-  this->ExportBuildFileGenerators.push_back(gen);
+  this->ExportBuildFileGenerators.emplace_back(std::move(gen));
 }
 
 namespace {
@@ -2616,7 +2622,7 @@
   };
 
   for (auto const& entry : sdkDatabase) {
-    if (sdkRoot.find(entry.name) == 0 ||
+    if (cmHasPrefix(sdkRoot, entry.name) ||
         sdkRoot.find(std::string("/") + entry.name) != std::string::npos) {
       return entry.sdk;
     }
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 081e69d..d628681 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -954,10 +954,11 @@
   const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
   GetEvaluationFiles() const;
 
-  std::vector<cmExportBuildFileGenerator*> GetExportBuildFileGenerators()
-    const;
+  std::vector<std::unique_ptr<cmExportBuildFileGenerator>> const&
+  GetExportBuildFileGenerators() const;
   void RemoveExportBuildFileGeneratorCMP0024(cmExportBuildFileGenerator* gen);
-  void AddExportBuildFileGenerator(cmExportBuildFileGenerator* gen);
+  void AddExportBuildFileGenerator(
+    std::unique_ptr<cmExportBuildFileGenerator> gen);
 
   // Maintain a stack of package roots to allow nested PACKAGE_ROOT_PATH
   // searches
@@ -1062,7 +1063,8 @@
   mutable cmsys::RegularExpression cmNamedCurly;
 
   std::vector<cmMakefile*> UnConfiguredDirectories;
-  std::vector<cmExportBuildFileGenerator*> ExportBuildFileGenerators;
+  std::vector<std::unique_ptr<cmExportBuildFileGenerator>>
+    ExportBuildFileGenerators;
 
   std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>
     EvaluationFiles;
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 0471a45..4fe10ad 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -547,7 +547,7 @@
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
     vars.CMTargetType =
-      cmState::GetTargetTypeName(this->GeneratorTarget->GetType());
+      cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
     vars.Language = linkLanguage.c_str();
     vars.Objects = buildObjs.c_str();
     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index d3f3a4f..4434f1d 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -756,7 +756,7 @@
 
     vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
     vars.CMTargetType =
-      cmState::GetTargetTypeName(this->GeneratorTarget->GetType());
+      cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
     vars.Language = linkLanguage.c_str();
     vars.AIXExports = aixExports.c_str();
     vars.Objects = buildObjs.c_str();
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 451f19e..4fb84ee 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -46,9 +46,8 @@
     this->LocalGenerator->GetGlobalGenerator());
   cmake* cm = this->GlobalGenerator->GetCMakeInstance();
   this->NoRuleMessages = false;
-  if (const char* ruleStatus =
-        cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) {
-    this->NoRuleMessages = cmIsOff(ruleStatus);
+  if (cmProp ruleStatus = cm->GetState()->GetGlobalProperty("RULE_MESSAGES")) {
+    this->NoRuleMessages = cmIsOff(*ruleStatus);
   }
   MacOSXContentGenerator = cm::make_unique<MacOSXContentGeneratorType>(this);
 }
@@ -300,8 +299,7 @@
       dependFileNameFull, false, this->GlobalGenerator->GetMakefileEncoding());
     depFileStream << "# Empty dependencies file for "
                   << this->GeneratorTarget->GetName() << ".\n"
-                  << "# This may be replaced when dependencies are built."
-                  << std::endl;
+                  << "# This may be replaced when dependencies are built.\n";
   }
 
   // Open the flags file.  This should be copy-if-different because the
@@ -639,7 +637,7 @@
   cmRulePlaceholderExpander::RuleVariables vars;
   vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
   vars.CMTargetType =
-    cmState::GetTargetTypeName(this->GeneratorTarget->GetType());
+    cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
   vars.Language = lang.c_str();
   vars.Target = targetOutPathReal.c_str();
   vars.TargetPDB = targetOutPathPDB.c_str();
@@ -716,8 +714,8 @@
       // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS
       rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
                                                    compileCommand, vars);
-      std::string workingDirectory = cmSystemTools::CollapseFullPath(
-        this->LocalGenerator->GetCurrentBinaryDirectory());
+      std::string workingDirectory =
+        this->LocalGenerator->GetCurrentBinaryDirectory();
       compileCommand.replace(compileCommand.find(langFlags), langFlags.size(),
                              this->GetFlags(lang, this->GetConfigName()));
       std::string langDefines = std::string("$(") + lang + "_DEFINES)";
@@ -1129,8 +1127,7 @@
   // translation table for the dependency scanning process.
   depCmd << "cd "
          << (this->LocalGenerator->ConvertToOutputFormat(
-              cmSystemTools::CollapseFullPath(
-                this->LocalGenerator->GetBinaryDirectory()),
+              this->LocalGenerator->GetBinaryDirectory(),
               cmOutputConverter::SHELL))
          << " && ";
 #endif
@@ -1146,23 +1143,19 @@
   depCmd << "$(CMAKE_COMMAND) -E cmake_depends \""
          << this->GlobalGenerator->GetName() << "\" "
          << this->LocalGenerator->ConvertToOutputFormat(
-              cmSystemTools::CollapseFullPath(
-                this->LocalGenerator->GetSourceDirectory()),
+              this->LocalGenerator->GetSourceDirectory(),
               cmOutputConverter::SHELL)
          << " "
          << this->LocalGenerator->ConvertToOutputFormat(
-              cmSystemTools::CollapseFullPath(
-                this->LocalGenerator->GetCurrentSourceDirectory()),
+              this->LocalGenerator->GetCurrentSourceDirectory(),
               cmOutputConverter::SHELL)
          << " "
          << this->LocalGenerator->ConvertToOutputFormat(
-              cmSystemTools::CollapseFullPath(
-                this->LocalGenerator->GetBinaryDirectory()),
+              this->LocalGenerator->GetBinaryDirectory(),
               cmOutputConverter::SHELL)
          << " "
          << this->LocalGenerator->ConvertToOutputFormat(
-              cmSystemTools::CollapseFullPath(
-                this->LocalGenerator->GetCurrentBinaryDirectory()),
+              this->LocalGenerator->GetCurrentBinaryDirectory(),
               cmOutputConverter::SHELL)
          << " "
          << this->LocalGenerator->ConvertToOutputFormat(
@@ -1250,8 +1243,10 @@
 
   // Setup implicit dependency scanning.
   for (auto const& idi : ccg.GetCC().GetImplicitDepends()) {
-    std::string objFullPath = cmSystemTools::CollapseFullPath(outputs[0]);
-    std::string srcFullPath = cmSystemTools::CollapseFullPath(idi.second);
+    std::string objFullPath = cmSystemTools::CollapseFullPath(
+      outputs[0], this->LocalGenerator->GetCurrentBinaryDirectory());
+    std::string srcFullPath = cmSystemTools::CollapseFullPath(
+      idi.second, this->LocalGenerator->GetCurrentBinaryDirectory());
     this->LocalGenerator->AddImplicitDepends(this->GeneratorTarget, idi.first,
                                              objFullPath, srcFullPath);
   }
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index 062c46c..9c4ff83 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -156,23 +156,25 @@
 std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule(
   const std::string& config) const
 {
-  return this->TargetLinkLanguage(config) + "_" +
-    cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) +
-    "_LINKER__" +
+  return cmStrCat(
+    this->TargetLinkLanguage(config), "_",
+    cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()),
+    "_LINKER__",
     cmGlobalNinjaGenerator::EncodeRuleName(
-           this->GetGeneratorTarget()->GetName()) +
-    "_" + config;
+      this->GetGeneratorTarget()->GetName()),
+    "_", config);
 }
 
 std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule(
   const std::string& config) const
 {
-  return this->TargetLinkLanguage(config) + "_" +
-    cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) +
-    "_DEVICE_LINKER__" +
+  return cmStrCat(
+    this->TargetLinkLanguage(config), "_",
+    cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()),
+    "_DEVICE_LINKER__",
     cmGlobalNinjaGenerator::EncodeRuleName(
-           this->GetGeneratorTarget()->GetName()) +
-    "_" + config;
+      this->GetGeneratorTarget()->GetName()),
+    "_", config);
 }
 
 struct cmNinjaRemoveNoOpCommands
@@ -191,7 +193,8 @@
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
     vars.CMTargetType =
-      cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
+      cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
+        .c_str();
 
     vars.Language = "CUDA";
 
@@ -282,7 +285,7 @@
     cmNinjaRule rule(std::move(linkRuleName));
     cmRulePlaceholderExpander::RuleVariables vars;
     vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
-    vars.CMTargetType = cmState::GetTargetTypeName(targetType);
+    vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
 
     std::string lang = this->TargetLinkLanguage(config);
     vars.Language = config.c_str();
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 0e1136f..8833fa4 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -495,7 +495,7 @@
   cmRulePlaceholderExpander::RuleVariables vars;
   vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
   vars.CMTargetType =
-    cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
+    cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str();
   vars.Language = lang.c_str();
   vars.Source = "$in";
   vars.Object = "$out";
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 1366ff0..d3daad8 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -305,7 +305,10 @@
          17, 0, cmPolicies::WARN)                                             \
   SELECT(POLICY, CMP0102,                                                     \
          "mark_as_advanced() does nothing if a cache entry does not exist.",  \
-         3, 17, 0, cmPolicies::WARN)
+         3, 17, 0, cmPolicies::WARN)                                          \
+  SELECT(POLICY, CMP0103,                                                     \
+         "multiple export() with same FILE without APPEND is not allowed.",   \
+         3, 18, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx
index 7a6cb42..18b135d 100644
--- a/Source/cmQtAutoGenGlobalInitializer.cxx
+++ b/Source/cmQtAutoGenGlobalInitializer.cxx
@@ -164,10 +164,10 @@
 
     // Set FOLDER property in the target
     {
-      char const* folder =
+      cmProp folder =
         makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
       if (folder != nullptr) {
-        target->SetProperty("FOLDER", folder);
+        target->SetProperty("FOLDER", *folder);
       }
     }
   }
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 629367d..dddba0a 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -339,15 +339,18 @@
 
   // Targets FOLDER
   {
-    const char* folder =
+    cmProp prop =
       this->Makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
-    if (folder == nullptr) {
-      folder = this->Makefile->GetState()->GetGlobalProperty(
+    if (prop == nullptr) {
+      prop = this->Makefile->GetState()->GetGlobalProperty(
         "AUTOGEN_TARGETS_FOLDER");
     }
+    const char* folder;
     // Inherit FOLDER property from target (#13688)
-    if (folder == nullptr) {
+    if (prop == nullptr) {
       folder = this->GenTarget->GetProperty("FOLDER");
+    } else {
+      folder = prop->c_str();
     }
     if (folder != nullptr) {
       this->TargetsFolder = folder;
@@ -1604,10 +1607,9 @@
         cmStrCat(genNameUpper, "_SOURCE_GROUP"), "AUTOGEN_SOURCE_GROUP"
       };
       for (std::string const& prop : props) {
-        const char* propName =
-          this->Makefile->GetState()->GetGlobalProperty(prop);
-        if ((propName != nullptr) && (*propName != '\0')) {
-          groupName = propName;
+        cmProp propName = this->Makefile->GetState()->GetGlobalProperty(prop);
+        if (propName && !propName->empty()) {
+          groupName = *propName;
           property = prop;
           break;
         }
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index 893bd6b..36dd627 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -700,27 +700,27 @@
   if (!ofs) {
     return false;
   }
-  ofs << "# Generated by CMake. Changes will be overwritten." << std::endl;
+  ofs << "# Generated by CMake. Changes will be overwritten.\n";
   for (auto const& pair : Map_) {
-    ofs << pair.first << std::endl;
+    ofs << pair.first << '\n';
     FileT const& file = *pair.second;
     if (!file.Moc.Macro.empty()) {
-      ofs << " mmc:" << file.Moc.Macro << std::endl;
+      ofs << " mmc:" << file.Moc.Macro << '\n';
     }
     for (IncludeKeyT const& item : file.Moc.Include.Underscore) {
-      ofs << " miu:" << item.Key << std::endl;
+      ofs << " miu:" << item.Key << '\n';
     }
     for (IncludeKeyT const& item : file.Moc.Include.Dot) {
-      ofs << " mid:" << item.Key << std::endl;
+      ofs << " mid:" << item.Key << '\n';
     }
     for (std::string const& item : file.Moc.Depends) {
-      ofs << " mdp:" << item << std::endl;
+      ofs << " mdp:" << item << '\n';
     }
     for (IncludeKeyT const& item : file.Uic.Include) {
-      ofs << " uic:" << item.Key << std::endl;
+      ofs << " uic:" << item.Key << '\n';
     }
     for (std::string const& item : file.Uic.Depends) {
-      ofs << " udp:" << item << std::endl;
+      ofs << " udp:" << item << '\n';
     }
   }
   return ofs.Close();
@@ -2211,9 +2211,9 @@
                       " for writing."));
     return;
   }
-  ofs << BaseConst().DepFileRuleName << ": \\" << std::endl;
+  ofs << BaseConst().DepFileRuleName << ": \\\n";
   for (const std::string& file : dependencies) {
-    ofs << '\t' << escapeDependencyPath(file) << " \\" << std::endl;
+    ofs << '\t' << escapeDependencyPath(file) << " \\\n";
     if (!ofs.good()) {
       LogError(GenT::GEN,
                cmStrCat("Writing depfile", MessagePath(BaseConst().DepFile),
@@ -2224,8 +2224,7 @@
 
   // Add the CMake executable to re-new cache data if necessary.
   // Also, this is the last entry, so don't add a backslash.
-  ofs << '\t' << escapeDependencyPath(BaseConst().CMakeExecutable)
-      << std::endl;
+  ofs << '\t' << escapeDependencyPath(BaseConst().CMakeExecutable) << '\n';
 }
 
 void cmQtAutoMocUicT::JobFinishT::Process()
diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx
index 7f4abf9..c39d162 100644
--- a/Source/cmRST.cxx
+++ b/Source/cmRST.cxx
@@ -89,7 +89,8 @@
         this->ProcessLine(line);
       } else {
         if (line[0] != '#') {
-          this->ProcessLine(line.substr(0, pos));
+          line.resize(pos);
+          this->ProcessLine(line);
         }
         rst.clear();
         this->Reset();
@@ -102,8 +103,9 @@
           this->ProcessLine("");
           continue;
         }
-        if (line.substr(0, 2) == "# ") {
-          this->ProcessLine(line.substr(2));
+        if (cmHasLiteralPrefix(line, "# ")) {
+          line.erase(0, 2);
+          this->ProcessLine(line);
           continue;
         }
         rst.clear();
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index 5ab1b3a..254131b 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -236,8 +236,7 @@
   }
   if (variable == "CMAKE_COMMAND") {
     return outputConverter->ConvertToOutputFormat(
-      cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()),
-      cmOutputConverter::SHELL);
+      cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
   }
 
   auto compIt = this->Compilers.find(variable);
@@ -334,7 +333,17 @@
       std::string replace =
         this->ExpandRuleVariable(outputConverter, var, replaceValues);
       expandedInput += s.substr(pos, start - pos);
+
+      // Prevent consecutive whitespace in the output if the rule variable
+      // expands to an empty string.
+      bool consecutive = replace.empty() && start > 0 && s[start - 1] == ' ' &&
+        end + 1 < s.size() && s[end + 1] == ' ';
+      if (consecutive) {
+        expandedInput.pop_back();
+      }
+
       expandedInput += replace;
+
       // move to next one
       start = s.find('<', start + var.size() + 2);
       pos = end + 1;
diff --git a/Source/cmRuntimeDependencyArchive.cxx b/Source/cmRuntimeDependencyArchive.cxx
index 7a987c2..34b3105 100644
--- a/Source/cmRuntimeDependencyArchive.cxx
+++ b/Source/cmRuntimeDependencyArchive.cxx
@@ -39,7 +39,7 @@
   std::string vsloc;
   bool found = false;
 #  ifndef CMAKE_BOOTSTRAP
-  if (gg->GetName().find(prefix) == 0) {
+  if (cmHasPrefix(gg->GetName(), prefix)) {
     cmGlobalVisualStudioVersionedGenerator* vsgen =
       static_cast<cmGlobalVisualStudioVersionedGenerator*>(gg);
     if (vsgen->GetVSInstance(vsloc)) {
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 83a7f7b..c5f3463 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -450,7 +450,7 @@
     bool haveProperties = false;
     for (auto const& prop : state->GetCacheEntryPropertyList(key)) {
       haveProperties = true;
-      props[prop] = state->GetCacheEntryProperty(key, prop);
+      props[prop] = *state->GetCacheEntryProperty(key, prop);
     }
     if (haveProperties) {
       entry[kPROPERTIES_KEY] = props;
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
index e7330ef..4dbbbd7 100644
--- a/Source/cmSetPropertyCommand.cxx
+++ b/Source/cmSetPropertyCommand.cxx
@@ -235,14 +235,8 @@
   if (!names.empty()) {
     // Construct the directory name.  Interpret relative paths with
     // respect to the current directory.
-    std::string dir = *names.begin();
-    if (!cmSystemTools::FileIsFullPath(dir)) {
-      dir = cmStrCat(status.GetMakefile().GetCurrentSourceDirectory(), '/',
-                     *names.begin());
-    }
-
-    // The local generators are associated with collapsed paths.
-    dir = cmSystemTools::CollapseFullPath(dir);
+    std::string dir = cmSystemTools::CollapseFullPath(
+      *names.begin(), status.GetMakefile().GetCurrentSourceDirectory());
 
     mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir);
     if (!mf) {
diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx
index 5f807b8..e852c05 100644
--- a/Source/cmSourceFileLocation.cxx
+++ b/Source/cmSourceFileLocation.cxx
@@ -4,6 +4,8 @@
 
 #include <cassert>
 
+#include <cm/string_view>
+
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
@@ -152,7 +154,7 @@
 
   // Only a fixed set of extensions will be tried to match a file on
   // disk.  One of these must match if loc refers to this source file.
-  std::string const& ext = this->Name.substr(loc.Name.size() + 1);
+  auto ext = cm::string_view(this->Name).substr(loc.Name.size() + 1);
   cmMakefile const* mf = this->Makefile;
   auto cm = mf->GetCMakeInstance();
   return cm->IsSourceExtension(ext) || cm->IsHeaderExtension(ext);
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
index cc62952..8350410 100644
--- a/Source/cmSourceGroupCommand.cxx
+++ b/Source/cmSourceGroupCommand.cxx
@@ -30,18 +30,6 @@
   return cmTokenize(path, "\\/");
 }
 
-std::string getFullFilePath(const std::string& currentPath,
-                            const std::string& path)
-{
-  std::string fullPath = path;
-
-  if (!cmSystemTools::FileIsFullPath(path)) {
-    fullPath = cmStrCat(currentPath, '/', path);
-  }
-
-  return cmSystemTools::CollapseFullPath(fullPath);
-}
-
 std::set<std::string> getSourceGroupFilesPaths(
   const std::string& root, const std::vector<std::string>& files)
 {
@@ -124,7 +112,8 @@
         errorMsg = "Could not create source group for file: " + sgFilesPath;
         return false;
       }
-      const std::string fullPath = getFullFilePath(root, sgFilesPath);
+      const std::string fullPath =
+        cmSystemTools::CollapseFullPath(sgFilesPath, root);
       sg->AddGroupFile(fullPath);
     }
   }
@@ -255,10 +244,8 @@
       parsedArguments[kFilesOptionName];
     for (auto const& filesArg : filesArguments) {
       std::string src = filesArg;
-      if (!cmSystemTools::FileIsFullPath(src)) {
-        src = cmStrCat(mf.GetCurrentSourceDirectory(), '/', filesArg);
-      }
-      src = cmSystemTools::CollapseFullPath(src);
+      src =
+        cmSystemTools::CollapseFullPath(src, mf.GetCurrentSourceDirectory());
       sg->AddGroupFile(src);
     }
   }
diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h
index 13f7622..55d23c1 100644
--- a/Source/cmStandardLexer.h
+++ b/Source/cmStandardLexer.h
@@ -3,6 +3,19 @@
 #ifndef cmStandardLexer_h
 #define cmStandardLexer_h
 
+#if !defined(_WIN32) && !defined(__sun)
+/* POSIX APIs are needed */
+#  define _POSIX_C_SOURCE 200809L
+#endif
+#if defined(__sun) && defined(__GNUC__) && !defined(__cplusplus)
+/* C sources: for fileno and strdup */
+#  define _XOPEN_SOURCE 600
+#endif
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+/* For isascii */
+#  define _XOPEN_SOURCE 700
+#endif
+
 #include "cmsys/Configure.h" // IWYU pragma: keep
 
 /* Disable some warnings.  */
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index bc08223..5a113dd 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -34,30 +34,44 @@
 
 cmState::~cmState() = default;
 
-const char* cmState::GetTargetTypeName(cmStateEnums::TargetType targetType)
+const std::string& cmState::GetTargetTypeName(
+  cmStateEnums::TargetType targetType)
 {
+#define MAKE_STATIC_PROP(PROP) static const std::string prop##PROP = #PROP
+  MAKE_STATIC_PROP(STATIC_LIBRARY);
+  MAKE_STATIC_PROP(MODULE_LIBRARY);
+  MAKE_STATIC_PROP(SHARED_LIBRARY);
+  MAKE_STATIC_PROP(OBJECT_LIBRARY);
+  MAKE_STATIC_PROP(EXECUTABLE);
+  MAKE_STATIC_PROP(UTILITY);
+  MAKE_STATIC_PROP(GLOBAL_TARGET);
+  MAKE_STATIC_PROP(INTERFACE_LIBRARY);
+  MAKE_STATIC_PROP(UNKNOWN_LIBRARY);
+  static const std::string propEmpty;
+#undef MAKE_STATIC_PROP
+
   switch (targetType) {
     case cmStateEnums::STATIC_LIBRARY:
-      return "STATIC_LIBRARY";
+      return propSTATIC_LIBRARY;
     case cmStateEnums::MODULE_LIBRARY:
-      return "MODULE_LIBRARY";
+      return propMODULE_LIBRARY;
     case cmStateEnums::SHARED_LIBRARY:
-      return "SHARED_LIBRARY";
+      return propSHARED_LIBRARY;
     case cmStateEnums::OBJECT_LIBRARY:
-      return "OBJECT_LIBRARY";
+      return propOBJECT_LIBRARY;
     case cmStateEnums::EXECUTABLE:
-      return "EXECUTABLE";
+      return propEXECUTABLE;
     case cmStateEnums::UTILITY:
-      return "UTILITY";
+      return propUTILITY;
     case cmStateEnums::GLOBAL_TARGET:
-      return "GLOBAL_TARGET";
+      return propGLOBAL_TARGET;
     case cmStateEnums::INTERFACE_LIBRARY:
-      return "INTERFACE_LIBRARY";
+      return propINTERFACE_LIBRARY;
     case cmStateEnums::UNKNOWN_LIBRARY:
-      return "UNKNOWN_LIBRARY";
+      return propUNKNOWN_LIBRARY;
   }
   assert(false && "Unexpected target type");
-  return nullptr;
+  return propEmpty;
 }
 
 static const std::array<std::string, 7> cmCacheEntryTypes = {
@@ -192,8 +206,8 @@
   return it.GetPropertyList();
 }
 
-const char* cmState::GetCacheEntryProperty(std::string const& key,
-                                           std::string const& propertyName)
+cmProp cmState::GetCacheEntryProperty(std::string const& key,
+                                      std::string const& propertyName)
 {
   cmCacheManager::CacheIterator it = this->CacheManager->GetCacheIterator(key);
   if (!it.PropertyExists(propertyName)) {
@@ -572,7 +586,7 @@
   this->GlobalProperties.AppendProperty(prop, value, asString);
 }
 
-const char* cmState::GetGlobalProperty(const std::string& prop)
+cmProp cmState::GetGlobalProperty(const std::string& prop)
 {
   if (prop == "CACHE_VARIABLES") {
     std::vector<std::string> cacheKeys = this->GetCacheEntryKeys();
@@ -596,41 +610,59 @@
   }
 #define STRING_LIST_ELEMENT(F) ";" #F
   if (prop == "CMAKE_C_KNOWN_FEATURES") {
-    return &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_C_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
   if (prop == "CMAKE_C90_KNOWN_FEATURES") {
-    return &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_C90_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
   if (prop == "CMAKE_C99_KNOWN_FEATURES") {
-    return &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_C99_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
   if (prop == "CMAKE_C11_KNOWN_FEATURES") {
-    return &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_C11_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
   if (prop == "CMAKE_CXX_KNOWN_FEATURES") {
-    return &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_CXX_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
   if (prop == "CMAKE_CXX98_KNOWN_FEATURES") {
-    return &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_CXX98_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
   if (prop == "CMAKE_CXX11_KNOWN_FEATURES") {
-    return &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_CXX11_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
   if (prop == "CMAKE_CXX14_KNOWN_FEATURES") {
-    return &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_CXX14_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
   if (prop == "CMAKE_CUDA_KNOWN_FEATURES") {
-    return &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1];
+    static const std::string s_out(
+      &FOR_EACH_CUDA_FEATURE(STRING_LIST_ELEMENT)[1]);
+    return &s_out;
   }
 
 #undef STRING_LIST_ELEMENT
-  cmProp retVal = this->GlobalProperties.GetPropertyValue(prop);
-  return retVal ? retVal->c_str() : nullptr;
+  return this->GlobalProperties.GetPropertyValue(prop);
 }
 
 bool cmState::GetGlobalPropertyAsBool(const std::string& prop)
 {
-  return cmIsOn(this->GetGlobalProperty(prop));
+  cmProp p = this->GetGlobalProperty(prop);
+  return p && cmIsOn(*p);
 }
 
 void cmState::SetSourceDirectory(std::string const& sourceDirectory)
diff --git a/Source/cmState.h b/Source/cmState.h
index b577a72..e3fbfdc 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -53,7 +53,8 @@
     CPack,
   };
 
-  static const char* GetTargetTypeName(cmStateEnums::TargetType targetType);
+  static const std::string& GetTargetTypeName(
+    cmStateEnums::TargetType targetType);
 
   cmStateSnapshot CreateBaseSnapshot();
   cmStateSnapshot CreateBuildsystemDirectorySnapshot(
@@ -104,8 +105,8 @@
   void SetCacheEntryBoolProperty(std::string const& key,
                                  std::string const& propertyName, bool value);
   std::vector<std::string> GetCacheEntryPropertyList(std::string const& key);
-  const char* GetCacheEntryProperty(std::string const& key,
-                                    std::string const& propertyName);
+  cmProp GetCacheEntryProperty(std::string const& key,
+                               std::string const& propertyName);
   bool GetCacheEntryPropertyAsBool(std::string const& key,
                                    std::string const& propertyName);
   void AppendCacheEntryProperty(std::string const& key,
@@ -173,7 +174,7 @@
   void SetGlobalProperty(const std::string& prop, const char* value);
   void AppendGlobalProperty(const std::string& prop, const std::string& value,
                             bool asString = false);
-  const char* GetGlobalProperty(const std::string& prop);
+  cmProp GetGlobalProperty(const std::string& prop);
   bool GetGlobalPropertyAsBool(const std::string& prop);
 
   std::string const& GetSourceDirectory() const;
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index e7de3c7..2ce7530 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -641,7 +641,7 @@
     if (parentSnapshot.IsValid()) {
       return parentSnapshot.GetDirectory().GetProperty(prop, chain);
     }
-    return this->Snapshot_.State->GetGlobalProperty(prop);
+    retVal = this->Snapshot_.State->GetGlobalProperty(prop);
   }
 
   return retVal ? retVal->c_str() : nullptr;
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index d8cd705..d290c0c 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1,5 +1,15 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#if !defined(_WIN32) && !defined(__sun)
+// POSIX APIs are needed
+#  define _POSIX_C_SOURCE 200809L
+#endif
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+// For isascii
+#  define _XOPEN_SOURCE 700
+#endif
+
 #include "cmSystemTools.h"
 
 #include <cmext/algorithm>
@@ -1055,8 +1065,7 @@
         if (type < 0 && !cmSystemTools::FileIsDirectory(fname)) {
           continue;
         }
-        if (sfname.size() >= ppath.size() &&
-            sfname.substr(0, ppath.size()) == ppath) {
+        if (cmHasPrefix(sfname, ppath)) {
           files.push_back(fname);
           res = true;
         }
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 03f1525..8b51690 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -368,6 +368,7 @@
     initProp("DISABLE_PRECOMPILE_HEADERS");
     initProp("UNITY_BUILD");
     initPropValue("UNITY_BUILD_BATCH_SIZE", "8");
+    initPropValue("PCH_WARN_INVALID", "ON");
 #ifdef __APPLE__
     if (this->GetGlobalGenerator()->IsXcode()) {
       initProp("XCODE_SCHEME_ADDRESS_SANITIZER");
@@ -888,7 +889,7 @@
       cmListFileContext lfc = cmd.second;
       lfc.FilePath = cmDir.ConvertToRelPathIfNotContained(
         impl->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath);
-      s << " * " << lfc << std::endl;
+      s << " * " << lfc << '\n';
     }
   }
 }
@@ -1668,7 +1669,7 @@
     }
     // the type property returns what type the target is
     if (prop == propTYPE) {
-      return cmState::GetTargetTypeName(this->GetType());
+      return cmState::GetTargetTypeName(this->GetType()).c_str();
     }
     if (prop == propINCLUDE_DIRECTORIES) {
       if (impl->IncludeDirectoriesEntries.empty()) {
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 333d4d5..1142dbd 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -134,7 +134,7 @@
             ge.Parse(i.second)->Evaluate(this->LG, config));
   }
   this->GenerateInternalProperties(os);
-  os << ")" << std::endl;
+  os << ")\n";
 }
 
 void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os, Indent indent)
@@ -176,9 +176,9 @@
       }
       fout << c;
     }
-    fout << "\"";
+    fout << '"';
   }
-  fout << ")" << std::endl;
+  fout << ")\n";
 
   // Output properties for the test.
   fout << indent << "set_tests_properties(" << this->Test->GetName()
@@ -188,7 +188,7 @@
          << cmOutputConverter::EscapeForCMake(i.second);
   }
   this->GenerateInternalProperties(fout);
-  fout << ")" << std::endl;
+  fout << ")\n";
 }
 
 void cmTestGenerator::GenerateInternalProperties(std::ostream& os)
@@ -213,7 +213,7 @@
     prependTripleSeparator = true;
   }
 
-  os << "\"";
+  os << '"';
 }
 
 std::vector<std::string> cmTestGenerator::EvaluateCommandLineArguments(
diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx
index 390fd16..13f73dc 100644
--- a/Source/cmTimestamp.cxx
+++ b/Source/cmTimestamp.cxx
@@ -1,5 +1,15 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing for details.  */
+
+#if !defined(_WIN32) && !defined(__sun)
+// POSIX APIs are needed
+#  define _POSIX_C_SOURCE 200809L
+#endif
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+// For isascii
+#  define _XOPEN_SOURCE 700
+#endif
+
 #include "cmTimestamp.h"
 
 #include <cstdlib>
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 6f5d813..1273308 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -6,6 +6,7 @@
 #include <set>
 
 #include <cm/memory>
+#include <cm/string_view>
 #include <cm/vector>
 
 #include "windows.h"
@@ -22,6 +23,7 @@
 #include "cmLocalVisualStudio10Generator.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmVisualStudioGeneratorOptions.h"
 
@@ -61,10 +63,10 @@
     this->StartElement();
   }
   Elem(const Elem&) = delete;
-  Elem(Elem& par, const std::string& tag)
+  Elem(Elem& par, cm::string_view tag)
     : S(par.S)
     , Indent(par.Indent + 1)
-    , Tag(tag)
+    , Tag(std::string(tag))
   {
     par.SetHasElements();
     this->StartElement();
@@ -78,22 +80,22 @@
   }
   std::ostream& WriteString(const char* line);
   void StartElement() { this->WriteString("<") << this->Tag; }
-  void Element(const std::string& tag, const std::string& val)
+  void Element(cm::string_view tag, std::string val)
   {
-    Elem(*this, tag).Content(val);
+    Elem(*this, tag).Content(std::move(val));
   }
-  Elem& Attribute(const char* an, const std::string& av)
+  Elem& Attribute(const char* an, std::string av)
   {
-    this->S << " " << an << "=\"" << cmVS10EscapeAttr(av) << "\"";
+    this->S << " " << an << "=\"" << cmVS10EscapeAttr(std::move(av)) << "\"";
     return *this;
   }
-  void Content(const std::string& val)
+  void Content(std::string val)
   {
     if (!this->HasContent) {
       this->S << ">";
       this->HasContent = true;
     }
-    this->S << cmVS10EscapeXML(val);
+    this->S << cmVS10EscapeXML(std::move(val));
   }
   ~Elem()
   {
@@ -556,10 +558,11 @@
 
       std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys();
       for (std::string const& keyIt : keys) {
-        static const char* prefix = "VS_GLOBAL_";
-        if (keyIt.find(prefix) != 0)
+        static const cm::string_view prefix = "VS_GLOBAL_";
+        if (!cmHasPrefix(keyIt, prefix))
           continue;
-        std::string globalKey = keyIt.substr(strlen(prefix));
+        cm::string_view globalKey =
+          cm::string_view(keyIt).substr(prefix.length());
         // Skip invalid or separately-handled properties.
         if (globalKey.empty() || globalKey == "PROJECT_TYPES" ||
             globalKey == "ROOTNAMESPACE" || globalKey == "KEYWORD") {
@@ -790,21 +793,14 @@
     for (std::string const& ri : packageReferences) {
       size_t versionIndex = ri.find_last_of('_');
       if (versionIndex != std::string::npos) {
-        WritePackageReference(e1, ri.substr(0, versionIndex),
-                              ri.substr(versionIndex + 1));
+        Elem e2(e1, "PackageReference");
+        e2.Attribute("Include", ri.substr(0, versionIndex));
+        e2.Attribute("Version", ri.substr(versionIndex + 1));
       }
     }
   }
 }
 
-void cmVisualStudio10TargetGenerator::WritePackageReference(
-  Elem& e1, std::string const& ref, std::string const& version)
-{
-  Elem e2(e1, "PackageReference");
-  e2.Attribute("Include", ref);
-  e2.Attribute("Version", version);
-}
-
 void cmVisualStudio10TargetGenerator::WriteDotNetReferences(Elem& e0)
 {
   std::vector<std::string> references;
@@ -814,17 +810,15 @@
   }
   cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
   for (auto const& i : props.GetList()) {
-    if (i.first.find("VS_DOTNET_REFERENCE_") == 0) {
-      std::string name = i.first.substr(20);
-      if (!name.empty()) {
-        std::string path = i.second;
-        if (!cmsys::SystemTools::FileIsFullPath(path)) {
-          path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
-        }
-        ConvertToWindowsSlash(path);
-        this->DotNetHintReferences[""].push_back(
-          DotNetHintReference(name, path));
+    static const cm::string_view vsDnRef = "VS_DOTNET_REFERENCE_";
+    if (cmHasPrefix(i.first, vsDnRef)) {
+      std::string path = i.second;
+      if (!cmsys::SystemTools::FileIsFullPath(path)) {
+        path = this->Makefile->GetCurrentSourceDirectory() + "/" + path;
       }
+      ConvertToWindowsSlash(path);
+      this->DotNetHintReferences[""].emplace_back(
+        DotNetHintReference(i.first.substr(vsDnRef.length()), path));
     }
   }
   if (!references.empty() || !this->DotNetHintReferences.empty()) {
@@ -837,7 +831,7 @@
           cmsys::SystemTools::GetFilenameWithoutLastExtension(ri);
         std::string path = ri;
         ConvertToWindowsSlash(path);
-        this->DotNetHintReferences[""].push_back(
+        this->DotNetHintReferences[""].emplace_back(
           DotNetHintReference(name, path));
       } else {
         this->WriteDotNetReference(e1, ri, "", "");
@@ -910,12 +904,8 @@
   CustomTags tags;
   cmPropertyMap const& props = this->GeneratorTarget->Target->GetProperties();
   for (const auto& i : props.GetList()) {
-    if (i.first.find(refPropFullPrefix) == 0) {
-      std::string refTag = i.first.substr(refPropFullPrefix.length());
-      std::string refVal = i.second;
-      if (!refTag.empty() && !refVal.empty()) {
-        tags[refTag] = refVal;
-      }
+    if (cmHasPrefix(i.first, refPropFullPrefix) && !i.second.empty()) {
+      tags[i.first.substr(refPropFullPrefix.length())] = i.second;
     }
   }
   for (auto const& tag : tags) {
@@ -952,7 +942,7 @@
         // subdirectory
         // of the .csproj file, we have to use relative pathnames, otherwise
         // visual studio does not show the file in the IDE. Sorry.
-        if (obj.find(srcDir) == 0) {
+        if (cmHasPrefix(obj, srcDir)) {
           obj = this->ConvertPath(obj, true);
           ConvertToWindowsSlash(obj);
           useRelativePath = true;
@@ -999,10 +989,10 @@
           }
           if (!generator.empty()) {
             e2.Element("Generator", generator);
-            if (designerResource.find(srcDir) == 0) {
-              designerResource = designerResource.substr(srcDir.length() + 1);
-            } else if (designerResource.find(binDir) == 0) {
-              designerResource = designerResource.substr(binDir.length() + 1);
+            if (cmHasPrefix(designerResource, srcDir)) {
+              designerResource.erase(0, srcDir.length());
+            } else if (cmHasPrefix(designerResource, binDir)) {
+              designerResource.erase(0, binDir.length());
             } else {
               designerResource =
                 cmsys::SystemTools::GetFilenameName(designerResource);
@@ -1013,9 +1003,10 @@
         }
         const cmPropertyMap& props = oi->GetProperties();
         for (const std::string& p : props.GetKeys()) {
-          static const std::string propNamePrefix = "VS_CSHARP_";
-          if (p.find(propNamePrefix) == 0) {
-            std::string tagName = p.substr(propNamePrefix.length());
+          static const cm::string_view propNamePrefix = "VS_CSHARP_";
+          if (cmHasPrefix(p, propNamePrefix)) {
+            cm::string_view tagName =
+              cm::string_view(p).substr(propNamePrefix.length());
             if (!tagName.empty()) {
               const std::string& value = *props.GetPropertyValue(p);
               if (!value.empty()) {
@@ -1749,8 +1740,8 @@
   if (this->IsResxHeader(fileName)) {
     e2.Element("FileType", "CppForm");
   } else if (this->IsXamlHeader(fileName)) {
-    std::string xamlFileName = fileName.substr(0, fileName.find_last_of("."));
-    e2.Element("DependentUpon", xamlFileName);
+    e2.Element("DependentUpon",
+               fileName.substr(0, fileName.find_last_of(".")));
   }
 }
 
@@ -2413,8 +2404,8 @@
   }
   if (this->IsXamlSource(source->GetFullPath())) {
     const std::string& fileName = source->GetFullPath();
-    std::string xamlFileName = fileName.substr(0, fileName.find_last_of("."));
-    e2.Element("DependentUpon", xamlFileName);
+    e2.Element("DependentUpon",
+               fileName.substr(0, fileName.find_last_of(".")));
   }
   if (this->ProjectType == csproj) {
     std::string f = source->GetFullPath();
@@ -4798,8 +4789,8 @@
   if (this->ProjectType == csproj) {
     const cmPropertyMap& props = sf->GetProperties();
     for (const std::string& p : props.GetKeys()) {
-      static const std::string propNamePrefix = "VS_CSHARP_";
-      if (p.find(propNamePrefix) == 0) {
+      static const cm::string_view propNamePrefix = "VS_CSHARP_";
+      if (cmHasPrefix(p, propNamePrefix)) {
         std::string tagName = p.substr(propNamePrefix.length());
         if (!tagName.empty()) {
           const std::string& val = *props.GetPropertyValue(p);
@@ -4840,9 +4831,9 @@
   if (sourceGroup && !sourceGroup->GetFullName().empty()) {
     link = sourceGroup->GetFullName() + "/" +
       cmsys::SystemTools::GetFilenameName(fullFileName);
-  } else if (fullFileName.find(srcDir) == 0) {
+  } else if (cmHasPrefix(fullFileName, srcDir)) {
     link = fullFileName.substr(srcDir.length() + 1);
-  } else if (fullFileName.find(binDir) == 0) {
+  } else if (cmHasPrefix(fullFileName, binDir)) {
     link = fullFileName.substr(binDir.length() + 1);
   } else if (const char* l = source->GetProperty("VS_CSHARP_Link")) {
     link = l;
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index 4977c1a..25b3d02 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -73,8 +73,6 @@
                              std::vector<size_t> const& exclude_configs);
   void WriteAllSources(Elem& e0);
   void WritePackageReferences(Elem& e0);
-  void WritePackageReference(Elem& e1, std::string const& ref,
-                             std::string const& version);
   void WriteDotNetReferences(Elem& e0);
   void WriteDotNetReference(Elem& e1, std::string const& ref,
                             std::string const& hint,
diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx
index 4533e9b..d7822b1 100644
--- a/Source/cmVisualStudioSlnParser.cxx
+++ b/Source/cmVisualStudioSlnParser.cxx
@@ -517,7 +517,7 @@
                                                  State& state)
 {
   size_t idxEqualSign = line.find('=');
-  const std::string& fullTag = line.substr(0, idxEqualSign);
+  auto fullTag = cm::string_view(line).substr(0, idxEqualSign);
   if (!this->ParseTag(fullTag, parsedLine, state))
     return false;
   if (idxEqualSign != line.npos) {
@@ -560,7 +560,7 @@
                                                   State& state)
 {
   size_t idxEqualSign = line.find('=');
-  const std::string& fullTag = line.substr(0, idxEqualSign);
+  auto fullTag = cm::string_view(line).substr(0, idxEqualSign);
   if (!this->ParseTag(fullTag, parsedLine, state))
     return false;
   if (idxEqualSign != line.npos) {
@@ -586,17 +586,17 @@
   return true;
 }
 
-bool cmVisualStudioSlnParser::ParseTag(const std::string& fullTag,
+bool cmVisualStudioSlnParser::ParseTag(cm::string_view fullTag,
                                        ParsedLine& parsedLine, State& state)
 {
   size_t idxLeftParen = fullTag.find('(');
-  if (idxLeftParen == fullTag.npos) {
+  if (idxLeftParen == cm::string_view::npos) {
     parsedLine.SetTag(cmTrimWhitespace(fullTag));
     return true;
   }
   parsedLine.SetTag(cmTrimWhitespace(fullTag.substr(0, idxLeftParen)));
   size_t idxRightParen = fullTag.rfind(')');
-  if (idxRightParen == fullTag.npos) {
+  if (idxRightParen == cm::string_view::npos) {
     this->LastResult.SetError(ResultErrorInputStructure,
                               state.GetCurrentLine());
     return false;
diff --git a/Source/cmVisualStudioSlnParser.h b/Source/cmVisualStudioSlnParser.h
index 6c05633..4557cdb 100644
--- a/Source/cmVisualStudioSlnParser.h
+++ b/Source/cmVisualStudioSlnParser.h
@@ -9,6 +9,8 @@
 #include <iosfwd>
 #include <string>
 
+#include <cm/string_view>
+
 #include <stddef.h>
 
 class cmSlnData;
@@ -97,8 +99,7 @@
   bool ParseKeyValuePair(const std::string& line, ParsedLine& parsedLine,
                          State& state);
 
-  bool ParseTag(const std::string& fullTag, ParsedLine& parsedLine,
-                State& state);
+  bool ParseTag(cm::string_view fullTag, ParsedLine& parsedLine, State& state);
 
   bool ParseValue(const std::string& value, ParsedLine& parsedLine);
 };
diff --git a/Source/cmWriteFileCommand.cxx b/Source/cmWriteFileCommand.cxx
index 34e21b2..666ba87 100644
--- a/Source/cmWriteFileCommand.cxx
+++ b/Source/cmWriteFileCommand.cxx
@@ -72,7 +72,7 @@
     status.SetError(error);
     return false;
   }
-  file << message << std::endl;
+  file << message << '\n';
   file.close();
   if (mode && !writable) {
     cmSystemTools::SetPermissions(fileName.c_str(), mode);
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index f26fce9..2ec893f 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -24,6 +24,7 @@
 #include "cmsys/Glob.hxx"
 #include "cmsys/RegularExpression.hxx"
 
+#include "cm_static_string_view.hxx"
 #include "cm_sys_stat.h"
 
 #include "cmAlgorithms.h"
@@ -292,7 +293,7 @@
   bool findPackageMode = false;
   for (unsigned int i = 1; i < args.size(); ++i) {
     std::string const& arg = args[i];
-    if (arg.find("-D", 0) == 0) {
+    if (cmHasLiteralPrefix(arg, "-D")) {
       std::string entry = arg.substr(2);
       if (entry.empty()) {
         ++i;
@@ -381,7 +382,7 @@
         // -Wno-error=<name>
         this->DiagLevels[name] = std::min(this->DiagLevels[name], DIAG_WARN);
       }
-    } else if (arg.find("-U", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-U")) {
       std::string entryPattern = arg.substr(2);
       if (entryPattern.empty()) {
         ++i;
@@ -411,7 +412,7 @@
       for (std::string const& currentEntry : entriesToDelete) {
         this->State->RemoveCacheEntry(currentEntry);
       }
-    } else if (arg.find("-C", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-C")) {
       std::string path = arg.substr(2);
       if (path.empty()) {
         ++i;
@@ -426,7 +427,7 @@
       // Resolve script path specified on command line relative to $PWD.
       path = cmSystemTools::CollapseFullPath(path);
       this->ReadListFile(args, path);
-    } else if (arg.find("-P", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-P")) {
       i++;
       if (i >= args.size()) {
         cmSystemTools::Error("-P must be followed by a file name.");
@@ -445,7 +446,7 @@
       this->SetHomeOutputDirectory(
         cmSystemTools::GetCurrentWorkingDirectory());
       this->ReadListFile(args, path);
-    } else if (arg.find("--find-package", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--find-package")) {
       findPackageMode = true;
     }
   }
@@ -524,11 +525,11 @@
     if (!quiet) {
       printf("%s not found.\n", packageName.c_str());
     }
-  } else if (mode == "EXIST") {
+  } else if (mode == "EXIST"_s) {
     if (!quiet) {
       printf("%s found.\n", packageName.c_str());
     }
-  } else if (mode == "COMPILE") {
+  } else if (mode == "COMPILE"_s) {
     std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS");
     std::vector<std::string> includeDirs = cmExpandedList(includes);
 
@@ -539,7 +540,7 @@
 
     std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS");
     printf("%s %s\n", includeFlags.c_str(), definitions.c_str());
-  } else if (mode == "LINK") {
+  } else if (mode == "LINK"_s) {
     const char* targetName = "dummy";
     std::vector<std::string> srcs;
     cmTarget* tgt = mf->AddExecutable(targetName, srcs, true);
@@ -623,7 +624,7 @@
 #endif
   for (unsigned int i = 1; i < args.size(); ++i) {
     std::string const& arg = args[i];
-    if (arg.find("-H", 0) == 0 || arg.find("-S", 0) == 0) {
+    if (cmHasLiteralPrefix(arg, "-H") || cmHasLiteralPrefix(arg, "-S")) {
       std::string path = arg.substr(2);
       if (path.empty()) {
         ++i;
@@ -641,9 +642,9 @@
       path = cmSystemTools::CollapseFullPath(path);
       cmSystemTools::ConvertToUnixSlashes(path);
       this->SetHomeDirectory(path);
-    } else if (arg.find("-O", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-O")) {
       // There is no local generate anymore.  Ignore -O option.
-    } else if (arg.find("-B", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-B")) {
       std::string path = arg.substr(2);
       if (path.empty()) {
         ++i;
@@ -662,54 +663,54 @@
       cmSystemTools::ConvertToUnixSlashes(path);
       this->SetHomeOutputDirectory(path);
     } else if ((i < args.size() - 2) &&
-               (arg.find("--check-build-system", 0) == 0)) {
+               cmHasLiteralPrefix(arg, "--check-build-system")) {
       this->CheckBuildSystemArgument = args[++i];
       this->ClearBuildSystem = (atoi(args[++i].c_str()) > 0);
     } else if ((i < args.size() - 1) &&
-               (arg.find("--check-stamp-file", 0) == 0)) {
+               cmHasLiteralPrefix(arg, "--check-stamp-file")) {
       this->CheckStampFile = args[++i];
     } else if ((i < args.size() - 1) &&
-               (arg.find("--check-stamp-list", 0) == 0)) {
+               cmHasLiteralPrefix(arg, "--check-stamp-list")) {
       this->CheckStampList = args[++i];
-    } else if (arg == "--regenerate-during-build") {
+    } else if (arg == "--regenerate-during-build"_s) {
       this->RegenerateDuringBuild = true;
     }
 #if defined(CMAKE_HAVE_VS_GENERATORS)
     else if ((i < args.size() - 1) &&
-             (arg.find("--vs-solution-file", 0) == 0)) {
+             cmHasLiteralPrefix(arg, "--vs-solution-file")) {
       this->VSSolutionFile = args[++i];
     }
 #endif
-    else if (arg.find("-D", 0) == 0) {
+    else if (cmHasLiteralPrefix(arg, "-D")) {
       // skip for now
       // in case '-D var=val' is given, also skip the next
       // in case '-Dvar=val' is given, don't skip the next
       if (arg.size() == 2) {
         ++i;
       }
-    } else if (arg.find("-U", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-U")) {
       // skip for now
       // in case '-U var' is given, also skip the next
       // in case '-Uvar' is given, don't skip the next
       if (arg.size() == 2) {
         ++i;
       }
-    } else if (arg.find("-C", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-C")) {
       // skip for now
       // in case '-C path' is given, also skip the next
       // in case '-Cpath' is given, don't skip the next
       if (arg.size() == 2) {
         ++i;
       }
-    } else if (arg.find("-P", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-P")) {
       // skip for now
       i++;
-    } else if (arg.find("--find-package", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--find-package")) {
       // skip for now
       i++;
-    } else if (arg.find("-W", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-W")) {
       // skip for now
-    } else if (arg.find("--graphviz=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--graphviz=")) {
       std::string path = arg.substr(strlen("--graphviz="));
       path = cmSystemTools::CollapseFullPath(path);
       cmSystemTools::ConvertToUnixSlashes(path);
@@ -718,13 +719,13 @@
         cmSystemTools::Error("No file specified for --graphviz");
         return;
       }
-    } else if (arg.find("--debug-trycompile", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--debug-trycompile")) {
       std::cout << "debug trycompile on\n";
       this->DebugTryCompileOn();
-    } else if (arg.find("--debug-output", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--debug-output")) {
       std::cout << "Running with debug output on.\n";
       this->SetDebugOutputOn(true);
-    } else if (arg.find("--log-level=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--log-level=")) {
       const auto logLevel =
         StringToLogLevel(arg.substr(sizeof("--log-level=") - 1));
       if (logLevel == LogLevel::LOG_UNDEFINED) {
@@ -733,7 +734,7 @@
       }
       this->SetLogLevel(logLevel);
       this->LogLevelWasSetViaCLI = true;
-    } else if (arg.find("--loglevel=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--loglevel=")) {
       // This is supported for backward compatibility. This option only
       // appeared in the 3.15.x release series and was renamed to
       // --log-level in 3.16.0
@@ -745,16 +746,16 @@
       }
       this->SetLogLevel(logLevel);
       this->LogLevelWasSetViaCLI = true;
-    } else if (arg == "--log-context") {
+    } else if (arg == "--log-context"_s) {
       this->SetShowLogContext(true);
-    } else if (arg.find("--debug-find", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--debug-find")) {
       std::cout << "Running with debug output on for the `find` commands.\n";
       this->SetDebugFindOutputOn(true);
-    } else if (arg.find("--trace-expand", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace-expand")) {
       std::cout << "Running with expanded trace output on.\n";
       this->SetTrace(true);
       this->SetTraceExpand(true);
-    } else if (arg.find("--trace-format=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace-format=")) {
       this->SetTrace(true);
       const auto traceFormat =
         StringToTraceFormat(arg.substr(strlen("--trace-format=")));
@@ -764,35 +765,35 @@
         return;
       }
       this->SetTraceFormat(traceFormat);
-    } else if (arg.find("--trace-source=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace-source=")) {
       std::string file = arg.substr(strlen("--trace-source="));
       cmSystemTools::ConvertToUnixSlashes(file);
       this->AddTraceSource(file);
       this->SetTrace(true);
-    } else if (arg.find("--trace-redirect=", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace-redirect=")) {
       std::string file = arg.substr(strlen("--trace-redirect="));
       cmSystemTools::ConvertToUnixSlashes(file);
       this->SetTraceFile(file);
       this->SetTrace(true);
-    } else if (arg.find("--trace", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--trace")) {
       std::cout << "Running with trace output on.\n";
       this->SetTrace(true);
       this->SetTraceExpand(false);
-    } else if (arg.find("--warn-uninitialized", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--warn-uninitialized")) {
       std::cout << "Warn about uninitialized values.\n";
       this->SetWarnUninitialized(true);
-    } else if (arg.find("--warn-unused-vars", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--warn-unused-vars")) {
       std::cout << "Finding unused variables.\n";
       this->SetWarnUnused(true);
-    } else if (arg.find("--no-warn-unused-cli", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--no-warn-unused-cli")) {
       std::cout << "Not searching for unused variables given on the "
                 << "command line.\n";
       this->SetWarnUnusedCli(false);
-    } else if (arg.find("--check-system-vars", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--check-system-vars")) {
       std::cout << "Also check system files when warning about unused and "
                 << "uninitialized variables.\n";
       this->SetCheckSystemVars(true);
-    } else if (arg.find("-A", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-A")) {
       std::string value = arg.substr(2);
       if (value.empty()) {
         ++i;
@@ -808,7 +809,7 @@
       }
       this->SetGeneratorPlatform(value);
       havePlatform = true;
-    } else if (arg.find("-T", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-T")) {
       std::string value = arg.substr(2);
       if (value.empty()) {
         ++i;
@@ -824,7 +825,7 @@
       }
       this->SetGeneratorToolset(value);
       haveToolset = true;
-    } else if (arg.find("-G", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "-G")) {
       std::string value = arg.substr(2);
       if (value.empty()) {
         ++i;
@@ -849,12 +850,12 @@
       }
       this->SetGlobalGenerator(std::move(gen));
 #if !defined(CMAKE_BOOTSTRAP)
-    } else if (arg.find("--profiling-format", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--profiling-format")) {
       profilingFormat = arg.substr(strlen("--profiling-format="));
       if (profilingFormat.empty()) {
         cmSystemTools::Error("No format specified for --profiling-format");
       }
-    } else if (arg.find("--profiling-output", 0) == 0) {
+    } else if (cmHasLiteralPrefix(arg, "--profiling-output")) {
       profilingOutput = arg.substr(strlen("--profiling-output="));
       profilingOutput = cmSystemTools::CollapseFullPath(profilingOutput);
       cmSystemTools::ConvertToUnixSlashes(profilingOutput);
@@ -886,7 +887,7 @@
         "--profiling-format specified but no --profiling-output!");
       return;
     }
-    if (profilingFormat == "google-trace") {
+    if (profilingFormat == "google-trace"_s) {
       try {
         this->ProfilingOutput =
           cm::make_unique<cmMakefileProfilingData>(profilingOutput);
@@ -1037,9 +1038,9 @@
     std::string fullPath = cmSystemTools::CollapseFullPath(arg);
     std::string name = cmSystemTools::GetFilenameName(fullPath);
     name = cmSystemTools::LowerCase(name);
-    if (name == "cmakecache.txt") {
+    if (name == "cmakecache.txt"_s) {
       cachePath = cmSystemTools::GetFilenamePath(fullPath);
-    } else if (name == "cmakelists.txt") {
+    } else if (name == "cmakelists.txt"_s) {
       listPath = cmSystemTools::GetFilenamePath(fullPath);
     }
   } else {
@@ -1048,7 +1049,7 @@
     std::string fullPath = cmSystemTools::CollapseFullPath(arg);
     std::string name = cmSystemTools::GetFilenameName(fullPath);
     name = cmSystemTools::LowerCase(name);
-    if (name == "cmakecache.txt" || name == "cmakelists.txt") {
+    if (name == "cmakecache.txt"_s || name == "cmakelists.txt"_s) {
       argIsFile = true;
       listPath = cmSystemTools::GetFilenamePath(fullPath);
     } else {
@@ -1409,9 +1410,9 @@
     cmProp existingValue = this->State->GetCacheEntryValue(save.key);
     if (existingValue) {
       save.type = this->State->GetCacheEntryType(save.key);
-      if (const char* help =
+      if (cmProp help =
             this->State->GetCacheEntryProperty(save.key, "HELPSTRING")) {
-        save.help = help;
+        save.help = *help;
       }
     }
     saved.push_back(std::move(save));
@@ -1510,10 +1511,10 @@
   this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(*value));
 
   int ret = this->ActualConfigure();
-  const char* delCacheVars =
+  cmProp delCacheVars =
     this->State->GetGlobalProperty("__CMAKE_DELETE_CACHE_CHANGE_VARS_");
-  if (delCacheVars && delCacheVars[0] != 0) {
-    return this->HandleDeleteCacheVariables(delCacheVars);
+  if (delCacheVars && !delCacheVars->empty()) {
+    return this->HandleDeleteCacheVariables(*delCacheVars);
   }
   return ret;
 }
@@ -1936,13 +1937,13 @@
                              cmStateEnums::CacheEntryType(type));
   this->UnwatchUnusedCli(key);
 
-  if (key == "CMAKE_WARN_DEPRECATED") {
+  if (key == "CMAKE_WARN_DEPRECATED"_s) {
     this->Messenger->SetSuppressDeprecatedWarnings(value && cmIsOff(value));
-  } else if (key == "CMAKE_ERROR_DEPRECATED") {
+  } else if (key == "CMAKE_ERROR_DEPRECATED"_s) {
     this->Messenger->SetDeprecatedWarningsAsErrors(cmIsOn(value));
-  } else if (key == "CMAKE_SUPPRESS_DEVELOPER_WARNINGS") {
+  } else if (key == "CMAKE_SUPPRESS_DEVELOPER_WARNINGS"_s) {
     this->Messenger->SetSuppressDevWarnings(cmIsOn(value));
-  } else if (key == "CMAKE_SUPPRESS_DEVELOPER_ERRORS") {
+  } else if (key == "CMAKE_SUPPRESS_DEVELOPER_ERRORS"_s) {
     this->Messenger->SetDevWarningsAsErrors(value && cmIsOff(value));
   }
 }
@@ -1978,9 +1979,10 @@
 {
   auto dotpos = file.rfind('.');
   if (dotpos != std::string::npos) {
-    auto ext = file.substr(dotpos + 1);
 #if defined(_WIN32) || defined(__APPLE__)
-    ext = cmSystemTools::LowerCase(ext);
+    auto ext = cmSystemTools::LowerCase(file.substr(dotpos + 1));
+#else
+    auto ext = cm::string_view(file).substr(dotpos + 1);
 #endif
     if (this->IsSourceExtension(ext) || this->IsHeaderExtension(ext)) {
       return file.substr(0, dotpos);
@@ -2428,7 +2430,7 @@
   this->State->AppendGlobalProperty(prop, value, asString);
 }
 
-const char* cmake::GetProperty(const std::string& prop)
+cmProp cmake::GetProperty(const std::string& prop)
 {
   return this->State->GetGlobalProperty(prop);
 }
@@ -2480,7 +2482,7 @@
   bool writeToStdout = true;
   for (unsigned int i = 1; i < args.size(); ++i) {
     std::string const& arg = args[i];
-    if (arg.find("-G", 0) == 0) {
+    if (cmHasLiteralPrefix(arg, "-G")) {
       std::string value = arg.substr(2);
       if (value.empty()) {
         ++i;
@@ -2669,10 +2671,10 @@
 std::vector<std::string> cmake::GetDebugConfigs()
 {
   std::vector<std::string> configs;
-  if (const char* config_list =
+  if (cmProp config_list =
         this->State->GetGlobalProperty("DEBUG_CONFIGURATIONS")) {
     // Expand the specified list and convert to upper-case.
-    cmExpandList(config_list, configs);
+    cmExpandList(*config_list, configs);
     std::transform(configs.begin(), configs.end(), configs.begin(),
                    cmSystemTools::UpperCase);
   }
diff --git a/Source/cmake.h b/Source/cmake.h
index 58769fd..cfcd264 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -16,6 +16,8 @@
 #include <utility>
 #include <vector>
 
+#include <cm/string_view>
+
 #include "cmGeneratedFileStream.h"
 #include "cmInstalledFile.h"
 #include "cmListFileCache.h"
@@ -138,13 +140,13 @@
 
   struct FileExtensions
   {
-    bool Test(std::string const& ext) const
+    bool Test(cm::string_view ext) const
     {
       return (this->unordered.find(ext) != this->unordered.end());
     }
 
     std::vector<std::string> ordered;
-    std::unordered_set<std::string> unordered;
+    std::unordered_set<cm::string_view> unordered;
   };
 
   using InstalledFilesMap = std::map<std::string, cmInstalledFile>;
@@ -266,7 +268,7 @@
     return this->SourceFileExtensions.ordered;
   }
 
-  bool IsSourceExtension(const std::string& ext) const
+  bool IsSourceExtension(cm::string_view ext) const
   {
     return this->SourceFileExtensions.Test(ext);
   }
@@ -276,7 +278,7 @@
     return this->HeaderFileExtensions.ordered;
   }
 
-  bool IsHeaderExtension(const std::string& ext) const
+  bool IsHeaderExtension(cm::string_view ext) const
   {
     return this->HeaderFileExtensions.Test(ext);
   }
@@ -286,7 +288,7 @@
     return this->CudaFileExtensions.ordered;
   }
 
-  bool IsCudaExtension(const std::string& ext) const
+  bool IsCudaExtension(cm::string_view ext) const
   {
     return this->CudaFileExtensions.Test(ext);
   }
@@ -296,7 +298,7 @@
     return this->FortranFileExtensions.ordered;
   }
 
-  bool IsFortranExtension(const std::string& ext) const
+  bool IsFortranExtension(cm::string_view ext) const
   {
     return this->FortranFileExtensions.Test(ext);
   }
@@ -364,7 +366,7 @@
   void SetProperty(const std::string& prop, const char* value);
   void AppendProperty(const std::string& prop, const std::string& value,
                       bool asString = false);
-  const char* GetProperty(const std::string& prop);
+  cmProp GetProperty(const std::string& prop);
   bool GetPropertyAsBool(const std::string& prop);
 
   //! Get or create an cmInstalledFile instance and return a pointer to it
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index 0e99117..84d0538 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -292,13 +292,13 @@
       cmStateEnums::CacheEntryType t = cm.GetState()->GetCacheEntryType(k);
       if (t != cmStateEnums::INTERNAL && t != cmStateEnums::STATIC &&
           t != cmStateEnums::UNINITIALIZED) {
-        const char* advancedProp =
+        cmProp advancedProp =
           cm.GetState()->GetCacheEntryProperty(k, "ADVANCED");
         if (list_all_cached || !advancedProp) {
           if (list_help) {
-            std::cout << "// "
-                      << cm.GetState()->GetCacheEntryProperty(k, "HELPSTRING")
-                      << std::endl;
+            cmProp help =
+              cm.GetState()->GetCacheEntryProperty(k, "HELPSTRING");
+            std::cout << "// " << (help ? *help : "") << std::endl;
           }
           std::cout << k << ":" << cmState::CacheEntryTypeToString(t) << "="
                     << cm.GetState()->GetSafeCacheEntryValue(k) << std::endl;
diff --git a/Source/cmcldeps.cxx b/Source/cmcldeps.cxx
index caf6453..5c27ac1 100644
--- a/Source/cmcldeps.cxx
+++ b/Source/cmcldeps.cxx
@@ -25,6 +25,7 @@
 
 #include "cmsys/Encoding.hxx"
 
+#include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
 // We don't want any wildcard expansion.
@@ -63,7 +64,7 @@
         msg);
 }
 
-static std::string trimLeadingSpace(const std::string& cmdline)
+static cm::string_view trimLeadingSpace(cm::string_view cmdline)
 {
   int i = 0;
   for (; cmdline[i] == ' '; ++i)
@@ -81,34 +82,30 @@
   }
 }
 
-bool startsWith(const std::string& str, const std::string& what)
-{
-  return str.compare(0, what.size(), what) == 0;
-}
-
 // Strips one argument from the cmdline and returns it. "surrounding quotes"
 // are removed from the argument if there were any.
 static std::string getArg(std::string& cmdline)
 {
-  std::string ret;
   bool in_quoted = false;
   unsigned int i = 0;
 
-  cmdline = trimLeadingSpace(cmdline);
+  cm::string_view cmdview = trimLeadingSpace(cmdline);
+  size_t spaceCnt = cmdline.size() - cmdview.size();
 
   for (;; ++i) {
-    if (i >= cmdline.size())
+    if (i >= cmdview.size())
       usage("Couldn't parse arguments.");
-    if (!in_quoted && cmdline[i] == ' ')
+    if (!in_quoted && cmdview[i] == ' ')
       break; // "a b" "x y"
-    if (cmdline[i] == '"')
+    if (cmdview[i] == '"')
       in_quoted = !in_quoted;
   }
 
-  ret = cmdline.substr(0, i);
-  if (ret[0] == '"' && ret[i - 1] == '"')
-    ret = ret.substr(1, ret.size() - 2);
-  cmdline = cmdline.substr(i);
+  cmdview = cmdview.substr(0, i);
+  if (cmdview[0] == '"' && cmdview[i - 1] == '"')
+    cmdview = cmdview.substr(1, i - 2);
+  std::string ret(cmdview);
+  cmdline.erase(0, spaceCnt + i);
   return ret;
 }
 
@@ -127,7 +124,7 @@
   prefix = getArg(cmdline);
   clpath = getArg(cmdline);
   binpath = getArg(cmdline);
-  rest = trimLeadingSpace(cmdline);
+  rest = std::string(trimLeadingSpace(cmdline));
 }
 
 // Not all backslashes need to be escaped in a depfile, but it's easier that
@@ -169,8 +166,8 @@
     // build.ninja file.  Therefore we need to canonicalize the path to use
     // backward slashes and relativize the path to the build directory.
     replaceAll(tmp, "/", "\\");
-    if (startsWith(tmp, cwd))
-      tmp = tmp.substr(cwd.size());
+    if (cmHasPrefix(tmp, cwd))
+      tmp.erase(0, cwd.size());
     escapePath(tmp);
     fprintf(out, "%s \\\n", tmp.c_str());
   }
@@ -194,7 +191,7 @@
   return replaced.replace(pos, what.size(), replacement);
 }
 
-static int process(const std::string& srcfilename, const std::string& dfile,
+static int process(cm::string_view srcfilename, const std::string& dfile,
                    const std::string& objfile, const std::string& prefix,
                    const std::string& cmd, const std::string& dir = "",
                    bool quiet = false)
@@ -221,13 +218,14 @@
   std::vector<std::string> includes;
   bool isFirstLine = true; // cl prints always first the source filename
   while (std::getline(ss, line)) {
-    if (startsWith(line, prefix)) {
-      std::string inc = trimLeadingSpace(line.substr(prefix.size()).c_str());
+    cm::string_view inc(line);
+    if (cmHasPrefix(inc, prefix)) {
+      inc = trimLeadingSpace(inc.substr(prefix.size()));
       if (inc.back() == '\r') // blech, stupid \r\n
         inc = inc.substr(0, inc.size() - 1);
-      includes.push_back(inc);
+      includes.emplace_back(std::string(inc));
     } else {
-      if (!isFirstLine || !startsWith(line, srcfilename)) {
+      if (!isFirstLine || !cmHasPrefix(inc, srcfilename)) {
         if (!quiet || exit_code != 0) {
           fprintf(stdout, "%s\n", line.c_str());
         }
@@ -258,14 +256,10 @@
                    cl, binpath, rest);
 
   // needed to suppress filename output of msvc tools
-  std::string srcfilename;
-  {
-    std::string::size_type pos = srcfile.rfind('\\');
-    if (pos == std::string::npos) {
-      srcfilename = srcfile;
-    } else {
-      srcfilename = srcfile.substr(pos + 1);
-    }
+  cm::string_view srcfilename(srcfile);
+  std::string::size_type pos = srcfile.rfind('\\');
+  if (pos != std::string::npos) {
+    srcfilename = srcfilename.substr(pos + 1);
   }
 
   std::string nol = " /nologo ";
@@ -286,7 +280,7 @@
     // call cl in object dir so the .i is generated there
     std::string objdir;
     {
-      std::string::size_type pos = objfile.rfind("\\");
+      pos = objfile.rfind("\\");
       if (pos != std::string::npos) {
         objdir = objfile.substr(0, pos);
       }
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 7eeb97f..18a2108 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -678,7 +678,7 @@
         } else if (!a.empty() && a[0] == '-') {
           // Environment variable and command names cannot start in '-',
           // so this must be an unknown option.
-          std::cerr << "cmake -E env: unknown option '" << a << "'"
+          std::cerr << "cmake -E env: unknown option '" << a << '\''
                     << std::endl;
           return 1;
         } else if (a.find('=') != std::string::npos) {
@@ -1054,8 +1054,7 @@
         homeOutDir = args[5];
         startOutDir = args[6];
         depInfo = args[7];
-        if (args.size() >= 9 && args[8].length() >= 8 &&
-            args[8].substr(0, 8) == "--color=") {
+        if (args.size() >= 9 && cmHasLiteralPrefix(args[8], "--color=")) {
           // Enable or disable color based on the switch value.
           color = (args[8].size() == 8 || cmIsOn(args[8].substr(8)));
         }
@@ -1304,7 +1303,7 @@
         } else if (arg == "--debug") {
           pipe.clear();
           isDebug = true;
-        } else if (arg.substr(0, pipePrefix.size()) == pipePrefix) {
+        } else if (cmHasPrefix(arg, pipePrefix)) {
           isDebug = false;
           pipe = arg.substr(pipePrefix.size());
           if (pipe.empty()) {
@@ -1511,7 +1510,7 @@
   bool newline = true;
   std::string progressDir;
   for (auto const& arg : cmMakeRange(args).advance(2)) {
-    if (arg.find("--switch=") == 0) {
+    if (cmHasLiteralPrefix(arg, "--switch=")) {
       // Enable or disable color based on the switch value.
       std::string value = arg.substr(9);
       if (!value.empty()) {
@@ -1566,7 +1565,7 @@
   //   args[3] == --verbose=?
   bool verbose = false;
   if (args.size() >= 4) {
-    if (args[3].find("--verbose=") == 0) {
+    if (cmHasLiteralPrefix(args[3], "--verbose=")) {
       if (!cmIsOff(args[3].substr(10))) {
         verbose = true;
       }
@@ -1654,11 +1653,13 @@
   cmVisualStudioWCEPlatformParser parser(name.c_str());
   parser.ParseVersion(version);
   if (parser.Found()) {
-    std::cout << "@echo off" << std::endl;
-    std::cout << "echo Environment Selection: " << name << std::endl;
-    std::cout << "set PATH=" << parser.GetPathDirectories() << std::endl;
-    std::cout << "set INCLUDE=" << parser.GetIncludeDirectories() << std::endl;
-    std::cout << "set LIB=" << parser.GetLibraryDirectories() << std::endl;
+    /* clang-format off */
+    std::cout << "@echo off\n"
+                 "echo Environment Selection: " << name << "\n"
+                 "set PATH=" << parser.GetPathDirectories() << "\n"
+                 "set INCLUDE=" << parser.GetIncludeDirectories() << "\n"
+                 "set LIB=" << parser.GetLibraryDirectories() << std::endl;
+    /* clang-format on */
     return 0;
   }
 #else
@@ -1697,6 +1698,11 @@
   }
   auto status = process.GetStatus();
   if (!status[0] || status[0]->ExitStatus != 0) {
+    auto errorStream = process.ErrorStream();
+    if (errorStream) {
+      std::cerr << errorStream->rdbuf();
+    }
+
     return 1;
   }
 
@@ -1765,6 +1771,10 @@
   }
   auto status = process.GetStatus();
   if (!status[0] || status[0]->ExitStatus != 0) {
+    auto errorStream = process.ErrorStream();
+    if (errorStream) {
+      std::cerr << errorStream->rdbuf();
+    }
     return 1;
   }
 
@@ -1826,7 +1836,7 @@
   std::vector<std::string> expandedArgs;
   for (std::string const& i : args) {
     // check for nmake temporary files
-    if (i[0] == '@' && i.find("@CMakeFiles") != 0) {
+    if (i[0] == '@' && !cmHasLiteralPrefix(i, "@CMakeFiles")) {
       cmsys::ifstream fin(i.substr(1).c_str());
       std::string line;
       while (cmSystemTools::GetLineFromStream(fin, line)) {
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index 1a772b4..d640948 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -35,6 +35,18 @@
   this->Internal = new DirectoryInternals;
 }
 
+Directory::Directory(Directory&& other)
+{
+  this->Internal = other.Internal;
+  other.Internal = nullptr;
+}
+
+Directory& Directory::operator=(Directory&& other)
+{
+  std::swap(this->Internal, other.Internal);
+  return *this;
+}
+
 Directory::~Directory()
 {
   delete this->Internal;
diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in
index ad8c51b..9b0f4c3 100644
--- a/Source/kwsys/Directory.hxx.in
+++ b/Source/kwsys/Directory.hxx.in
@@ -23,6 +23,11 @@
 {
 public:
   Directory();
+  Directory(Directory&& other);
+  Directory(const Directory&) = delete;
+  Directory& operator=(const Directory&) = delete;
+  Directory& operator=(Directory&& other);
+  bool operator==(const Directory&) = delete;
   ~Directory();
 
   /**
@@ -62,10 +67,7 @@
 private:
   // Private implementation details.
   DirectoryInternals* Internal;
-
-  Directory(const Directory&);      // Not implemented.
-  void operator=(const Directory&); // Not implemented.
-};                                  // End Class: Directory
+}; // End Class: Directory
 
 } // namespace @KWSYS_NAMESPACE@
 
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 658b816..8e30f92 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -385,10 +385,9 @@
   }
 
   if (skip > 0) {
-    expr = expr.substr(skip);
+    expr.erase(0, skip);
   }
 
-  cexpr = "";
   for (cc = 0; cc < expr.size(); cc++) {
     int ch = expr[cc];
     if (ch == '/') {
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index 3cf64a8..95b06e1 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -1367,7 +1367,7 @@
   if (!this->ReportPath) {
     size_t at = file.rfind("/");
     if (at != std::string::npos) {
-      file = file.substr(at + 1);
+      file.erase(0, at + 1);
     }
   }
   return file;
@@ -2170,7 +2170,7 @@
     this->ChipManufacturer = HP; // Hewlett-Packard
   else if (this->ChipID.Vendor == "Motorola")
     this->ChipManufacturer = Motorola; // Motorola Microelectronics
-  else if (family.substr(0, 7) == "PA-RISC")
+  else if (family.compare(0, 7, "PA-RISC") == 0)
     this->ChipManufacturer = HP; // Hewlett-Packard
   else
     this->ChipManufacturer = UnknownManufacturer; // Unknown manufacturer
@@ -2885,7 +2885,7 @@
   // post-process the name.
   std::string::size_type pos = str.find_first_not_of(" ");
   if (pos != std::string::npos) {
-    str = str.substr(pos);
+    str.erase(0, pos);
   }
 }
 #endif
@@ -3400,7 +3400,9 @@
           return this->ExtractValueFromCpuInfoFile(buffer, word, pos2);
         }
       }
-      return buffer.substr(pos + 2, pos2 - pos - 2);
+      buffer.erase(0, pos + 2);
+      buffer.resize(pos2 - pos - 2);
+      return buffer;
     }
   }
   this->CurrentPositionInFile = std::string::npos;
@@ -3549,7 +3551,7 @@
     if (!cacheSize.empty()) {
       pos = cacheSize.find(" KB");
       if (pos != std::string::npos) {
-        cacheSize = cacheSize.substr(0, pos);
+        cacheSize.resize(pos);
       }
       this->Features.L1CacheSize += atoi(cacheSize.c_str());
     }
@@ -4774,7 +4776,8 @@
     }
     pos = command.find(' ', pos + 1);
   }
-  args_string.push_back(command.substr(start + 1, command.size() - start - 1));
+  command.erase(0, start + 1);
+  args_string.push_back(command);
 
   std::vector<const char*> args;
   args.reserve(3 + args_string.size());
@@ -4963,7 +4966,9 @@
   while (buffer[pos] == ' ')
     pos++;
 
-  this->TotalPhysicalMemory = atoi(buffer.substr(pos, pos2 - pos).c_str());
+  buffer.erase(0, pos);
+  buffer.resize(pos2);
+  this->TotalPhysicalMemory = atoi(buffer.c_str());
   return true;
 #endif
   return false;
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 3fa1745..e073cbf 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -221,11 +221,17 @@
 
 #ifdef KWSYS_WINDOWS_DIRS
 #  include <wctype.h>
+#  ifdef _MSC_VER
+typedef KWSYS_NAMESPACE::SystemTools::mode_t mode_t;
+#  endif
 
-inline int Mkdir(const std::string& dir)
+inline int Mkdir(const std::string& dir, const mode_t* mode)
 {
-  return _wmkdir(
-    KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str());
+  int ret =
+    _wmkdir(KWSYS_NAMESPACE::Encoding::ToWindowsExtendedPath(dir).c_str());
+  if (ret == 0 && mode)
+    KWSYS_NAMESPACE::SystemTools::SetPermissions(dir, *mode);
+  return ret;
 }
 inline int Rmdir(const std::string& dir)
 {
@@ -295,9 +301,9 @@
 
 #  include <fcntl.h>
 #  include <unistd.h>
-inline int Mkdir(const std::string& dir)
+inline int Mkdir(const std::string& dir, const mode_t* mode)
 {
-  return mkdir(dir.c_str(), 00777);
+  return mkdir(dir.c_str(), mode ? *mode : 00777);
 }
 inline int Rmdir(const std::string& dir)
 {
@@ -912,16 +918,17 @@
   std::string::size_type pos = 0;
   std::string topdir;
   while ((pos = dir.find('/', pos)) != std::string::npos) {
-    topdir = dir.substr(0, pos);
+    // all underlying functions use C strings, so temporarily
+    // end the string here
+    dir[pos] = '\0';
 
-    if (Mkdir(topdir) == 0 && mode != nullptr) {
-      SystemTools::SetPermissions(topdir, *mode);
-    }
+    Mkdir(dir, mode);
+    dir[pos] = '/';
 
     ++pos;
   }
   topdir = dir;
-  if (Mkdir(topdir) != 0) {
+  if (Mkdir(topdir, mode) != 0) {
     // There is a bug in the Borland Run time library which makes MKDIR
     // return EACCES when it should return EEXISTS
     // if it is some other error besides directory exists
@@ -933,8 +940,6 @@
     ) {
       return false;
     }
-  } else if (mode != nullptr) {
-    SystemTools::SetPermissions(topdir, *mode);
   }
 
   return true;
@@ -1010,38 +1015,40 @@
 #    define KWSYS_ST_KEY_WOW64_64KEY 0x0100
 #  endif
 
-static bool SystemToolsParseRegistryKey(const std::string& key,
-                                        HKEY& primaryKey, std::string& second,
-                                        std::string& valuename)
+static bool hasPrefix(const std::string& s, const char* pattern,
+                      std::string::size_type spos)
 {
-  std::string primary = key;
+  size_t plen = strlen(pattern);
+  if (spos != plen)
+    return false;
+  return s.compare(0, plen, pattern) == 0;
+}
 
-  size_t start = primary.find('\\');
+static bool SystemToolsParseRegistryKey(const std::string& key,
+                                        HKEY& primaryKey, std::wstring& second,
+                                        std::string* valuename)
+{
+  size_t start = key.find('\\');
   if (start == std::string::npos) {
     return false;
   }
 
-  size_t valuenamepos = primary.find(';');
-  if (valuenamepos != std::string::npos) {
-    valuename = primary.substr(valuenamepos + 1);
+  size_t valuenamepos = key.find(';');
+  if (valuenamepos != std::string::npos && valuename) {
+    *valuename = key.substr(valuenamepos + 1);
   }
 
-  second = primary.substr(start + 1, valuenamepos - start - 1);
-  primary = primary.substr(0, start);
+  second = Encoding::ToWide(key.substr(start + 1, valuenamepos - start - 1));
 
-  if (primary == "HKEY_CURRENT_USER") {
+  if (hasPrefix(key, "HKEY_CURRENT_USER", start)) {
     primaryKey = HKEY_CURRENT_USER;
-  }
-  if (primary == "HKEY_CURRENT_CONFIG") {
+  } else if (hasPrefix(key, "HKEY_CURRENT_CONFIG", start)) {
     primaryKey = HKEY_CURRENT_CONFIG;
-  }
-  if (primary == "HKEY_CLASSES_ROOT") {
+  } else if (hasPrefix(key, "HKEY_CLASSES_ROOT", start)) {
     primaryKey = HKEY_CLASSES_ROOT;
-  }
-  if (primary == "HKEY_LOCAL_MACHINE") {
+  } else if (hasPrefix(key, "HKEY_LOCAL_MACHINE", start)) {
     primaryKey = HKEY_LOCAL_MACHINE;
-  }
-  if (primary == "HKEY_USERS") {
+  } else if (hasPrefix(key, "HKEY_USERS", start)) {
     primaryKey = HKEY_USERS;
   }
 
@@ -1073,14 +1080,13 @@
                                      KeyWOW64 view)
 {
   HKEY primaryKey = HKEY_CURRENT_USER;
-  std::string second;
-  std::string valuename;
-  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
+  std::wstring second;
+  if (!SystemToolsParseRegistryKey(key, primaryKey, second, nullptr)) {
     return false;
   }
 
   HKEY hKey;
-  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
+  if (RegOpenKeyExW(primaryKey, second.c_str(), 0,
                     SystemToolsMakeRegistryMode(KEY_READ, view),
                     &hKey) != ERROR_SUCCESS) {
     return false;
@@ -1120,14 +1126,14 @@
 {
   bool valueset = false;
   HKEY primaryKey = HKEY_CURRENT_USER;
-  std::string second;
+  std::wstring second;
   std::string valuename;
-  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
+  if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) {
     return false;
   }
 
   HKEY hKey;
-  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
+  if (RegOpenKeyExW(primaryKey, second.c_str(), 0,
                     SystemToolsMakeRegistryMode(KEY_READ, view),
                     &hKey) != ERROR_SUCCESS) {
     return false;
@@ -1174,16 +1180,16 @@
                                      const std::string& value, KeyWOW64 view)
 {
   HKEY primaryKey = HKEY_CURRENT_USER;
-  std::string second;
+  std::wstring second;
   std::string valuename;
-  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
+  if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) {
     return false;
   }
 
   HKEY hKey;
   DWORD dwDummy;
   wchar_t lpClass[] = L"";
-  if (RegCreateKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0, lpClass,
+  if (RegCreateKeyExW(primaryKey, second.c_str(), 0, lpClass,
                       REG_OPTION_NON_VOLATILE,
                       SystemToolsMakeRegistryMode(KEY_WRITE, view), nullptr,
                       &hKey, &dwDummy) != ERROR_SUCCESS) {
@@ -1218,14 +1224,14 @@
 bool SystemTools::DeleteRegistryValue(const std::string& key, KeyWOW64 view)
 {
   HKEY primaryKey = HKEY_CURRENT_USER;
-  std::string second;
+  std::wstring second;
   std::string valuename;
-  if (!SystemToolsParseRegistryKey(key, primaryKey, second, valuename)) {
+  if (!SystemToolsParseRegistryKey(key, primaryKey, second, &valuename)) {
     return false;
   }
 
   HKEY hKey;
-  if (RegOpenKeyExW(primaryKey, Encoding::ToWide(second).c_str(), 0,
+  if (RegOpenKeyExW(primaryKey, second.c_str(), 0,
                     SystemToolsMakeRegistryMode(KEY_WRITE, view),
                     &hKey) != ERROR_SUCCESS) {
     return false;
@@ -1866,7 +1872,7 @@
 
   size_t middle = max_len / 2;
 
-  n += s.substr(0, middle);
+  n.assign(s, 0, middle);
   n += s.substr(s.size() - (max_len - middle));
 
   if (max_len > 2) {
@@ -2064,8 +2070,10 @@
 #ifdef HAVE_GETPWNAM
   else if (pathCString[0] == '~') {
     std::string::size_type idx = path.find_first_of("/\0");
-    std::string user = path.substr(1, idx - 1);
-    passwd* pw = getpwnam(user.c_str());
+    char oldch = path[idx];
+    path[idx] = '\0';
+    passwd* pw = getpwnam(path.c_str() + 1);
+    path[idx] = oldch;
     if (pw) {
       path.replace(0, idx, pw->pw_dir);
     }
@@ -3131,17 +3139,17 @@
                                    std::string& dir, std::string& file, bool)
 {
   dir = in_name;
-  file = "";
+  file.clear();
   SystemTools::ConvertToUnixSlashes(dir);
 
   if (!SystemTools::FileIsDirectory(dir)) {
     std::string::size_type slashPos = dir.rfind("/");
     if (slashPos != std::string::npos) {
       file = dir.substr(slashPos + 1);
-      dir = dir.substr(0, slashPos);
+      dir.resize(slashPos);
     } else {
       file = dir;
-      dir = "";
+      dir.clear();
     }
   }
   if (!(dir.empty()) && !SystemTools::FileIsDirectory(dir)) {
@@ -3268,7 +3276,7 @@
   // Now convert any path found in the table back to the one desired:
   for (auto const& pair : SystemTools::Statics->TranslationMap) {
     // We need to check of the path is a substring of the other path
-    if (path.find(pair.first) == 0) {
+    if (path.compare(0, pair.first.size(), pair.first) == 0) {
       path = path.replace(0, pair.first.size(), pair.second);
     }
   }
@@ -3540,7 +3548,7 @@
     // Expand home directory references if requested.
     if (expand_home_dir && !root.empty() && root[0] == '~') {
       std::string homedir;
-      root = root.substr(0, root.size() - 1);
+      root.resize(root.size() - 1);
       if (root.size() == 1) {
 #if defined(_WIN32) && !defined(__CYGWIN__)
         if (!SystemTools::GetEnv("USERPROFILE", homedir))
@@ -3685,18 +3693,19 @@
   SystemTools::ConvertToUnixSlashes(fn);
 
   std::string::size_type slash_pos = fn.rfind("/");
-  if (slash_pos != std::string::npos) {
-    std::string ret = fn.substr(0, slash_pos);
-    if (ret.size() == 2 && ret[1] == ':') {
-      return ret + '/';
-    }
-    if (ret.empty()) {
-      return "/";
-    }
-    return ret;
-  } else {
+  if (slash_pos == 0) {
+    return "/";
+  }
+  if (slash_pos == 2 && fn[1] == ':') {
+    // keep the / after a drive letter
+    fn.resize(3);
+    return fn;
+  }
+  if (slash_pos == std::string::npos) {
     return "";
   }
+  fn.resize(slash_pos);
+  return fn;
 }
 
 /**
@@ -3726,7 +3735,8 @@
   std::string name = SystemTools::GetFilenameName(filename);
   std::string::size_type dot_pos = name.find('.');
   if (dot_pos != std::string::npos) {
-    return name.substr(dot_pos);
+    name.erase(0, dot_pos);
+    return name;
   } else {
     return "";
   }
@@ -3741,7 +3751,8 @@
   std::string name = SystemTools::GetFilenameName(filename);
   std::string::size_type dot_pos = name.rfind('.');
   if (dot_pos != std::string::npos) {
-    return name.substr(dot_pos);
+    name.erase(0, dot_pos);
+    return name;
   } else {
     return "";
   }
@@ -3757,10 +3768,9 @@
   std::string name = SystemTools::GetFilenameName(filename);
   std::string::size_type dot_pos = name.find('.');
   if (dot_pos != std::string::npos) {
-    return name.substr(0, dot_pos);
-  } else {
-    return name;
+    name.resize(dot_pos);
   }
+  return name;
 }
 
 /**
@@ -3774,10 +3784,9 @@
   std::string name = SystemTools::GetFilenameName(filename);
   std::string::size_type dot_pos = name.rfind('.');
   if (dot_pos != std::string::npos) {
-    return name.substr(0, dot_pos);
-  } else {
-    return name;
+    name.resize(dot_pos);
   }
+  return name;
 }
 
 bool SystemTools::FileHasSignature(const char* filename, const char* signature,
@@ -3999,7 +4008,8 @@
 
   // if the path passed in has quotes around it, first remove the quotes
   if (!path.empty() && path[0] == '"' && path.back() == '"') {
-    tempPath = path.substr(1, path.length() - 2);
+    tempPath.resize(path.length() - 1);
+    tempPath.erase(0, 1);
   }
 
   std::wstring wtempPath = Encoding::ToWide(tempPath);
@@ -4218,8 +4228,8 @@
   if (subdir[expectedSlashPosition] != '/') {
     return false;
   }
-  std::string s = subdir.substr(0, dir.size());
-  return SystemTools::ComparePath(s, dir);
+  subdir.resize(dir.size());
+  return SystemTools::ComparePath(subdir, dir);
 }
 
 void SystemTools::Delay(unsigned int msec)
@@ -4580,8 +4590,8 @@
   std::string ret;
   for (size_t i = 0; i < url.length(); i++) {
     if (urlByteRe.find(url.substr(i, 3))) {
-      ret +=
-        static_cast<char>(strtoul(url.substr(i + 1, 2).c_str(), nullptr, 16));
+      char bytes[] = { url[i + 1], url[i + 2], '\0' };
+      ret += static_cast<char>(strtoul(bytes, nullptr, 16));
       i += 2;
     } else {
       ret += url[i];
diff --git a/Tests/FindRuby/CMakeLists.txt b/Tests/FindRuby/CMakeLists.txt
index 193cb4f..3f4807c 100644
--- a/Tests/FindRuby/CMakeLists.txt
+++ b/Tests/FindRuby/CMakeLists.txt
@@ -24,7 +24,7 @@
     --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
     )
   set_tests_properties(FindRuby.Fail PROPERTIES
-    PASS_REGULAR_EXPRESSION "Could NOT find Ruby: Found unsuitable version \".*\", but required is.*least \"[0-9]+\\.[0-9]+\\.[0-9]+\" \\(found .*\\)")
+    PASS_REGULAR_EXPRESSION "Could NOT find Ruby.*(Required is at least version \"[0-9]+\\.[0-9]+\\.[0-9]+\")")
 
   # Looks for 1.9.9 EXACTLY, which unlike the "FindRuby" test above will fail on every machine
   # since this version doesn't exist (ruby goes from 1.9.3 to 2.0.0)
@@ -41,4 +41,17 @@
   set_tests_properties(FindRuby.FailExact PROPERTIES
     PASS_REGULAR_EXPRESSION "Could NOT find Ruby: Found unsuitable version \".*\", but required is.*exact version \"[0-9]+\\.[0-9]+\\.[0-9]+\" \\(found .*\\)")
 
+  # RVM specific test
+  if(CMake_TEST_FindRuby_RVM)
+    add_test(NAME FindRuby.Rvm COMMAND
+      ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+      --build-and-test
+      "${CMake_SOURCE_DIR}/Tests/FindRuby/Rvm"
+      "${CMake_BINARY_DIR}/Tests/FindRuby/Rvm"
+      ${build_generator_args}
+      --build-project TestRVM
+      --build-options ${build_options}
+      --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+      )
+  endif()
 endif()
diff --git a/Tests/FindRuby/Rvm/CMakeLists.txt b/Tests/FindRuby/Rvm/CMakeLists.txt
new file mode 100644
index 0000000..545fc94
--- /dev/null
+++ b/Tests/FindRuby/Rvm/CMakeLists.txt
@@ -0,0 +1,75 @@
+cmake_minimum_required(VERSION 3.17)
+project(TestRVM LANGUAGES NONE)
+
+include(CTest)
+
+# To run this test, you need to have at least one RVM ruby installed
+# and to ensure that the env variable 'MY_RUBY_HOME' is set to a valid RVM ruby when you run the test
+# (which is the case if you have done `rvm use x.y.z`, but could be manually set too)
+
+# Properly using rvm would require sourcing a shell script, eg `source "$HOME/.rvm/scripts/rvm"`
+# Instead, I'll just rely on the env variable MY_RUBY_HOME
+set(MY_RUBY_HOME "$ENV{MY_RUBY_HOME}")
+if(NOT MY_RUBY_HOME)
+  message(FATAL_ERROR "Env variable MY_RUBY_HOME should be set to a valid RVM ruby location, or you should call `rvm use x.y.z` before")
+endif()
+execute_process (COMMAND "${MY_RUBY_HOME}/bin/ruby" -e "puts RUBY_VERSION"
+                 RESULT_VARIABLE result
+                 OUTPUT_VARIABLE RVM_RUBY_VERSION
+                 ERROR_QUIET
+                 OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if (result)
+  message (FATAL_ERROR "Unable to detect RVM ruby version from `${MY_RUBY_HOME}/bin/ruby`: ${RVM_RUBY_VERSION}")
+endif()
+
+execute_process(COMMAND "${CMAKE_COMMAND}" -E env --unset=MY_RUBY_HOME --unset=PATH
+                        "which" "ruby"
+                 RESULT_VARIABLE result
+                 OUTPUT_VARIABLE SYSTEM_RUBY
+                 ERROR_QUIET
+                 OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if (SYSTEM_RUBY MATCHES "^${MY_RUBY_HOME}/.+")
+  message(FATAL_ERROR "Unable to find system ruby, found ${SYSTEM_RUBY} which is part of MY_RUBY_HOME=${MY_RUBY_HOME}")
+endif()
+
+# Check version of the system ruby executable.
+execute_process (COMMAND "${SYSTEM_RUBY}" -e "puts RUBY_VERSION"
+                 RESULT_VARIABLE result
+                 OUTPUT_VARIABLE SYSTEM_RUBY_VERSION
+                 ERROR_QUIET
+                 OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if (result)
+  message (FATAL_ERROR "Unable to detect system ruby version from '${SYSTEM_RUBY}': ${SYSTEM_RUBY_VERSION}")
+endif()
+
+if(SYSTEM_RUBY_VERSION VERSION_EQUAL RVM_RUBY_VERSION)
+  message(FATAL_ERROR "Your RVM Ruby Version and your System ruby version are the same (${RVM_RUBY_VERSION}).")
+endif()
+
+message("Found System Ruby (${SYSTEM_RUBY_VERSION}): ${SYSTEM_RUBY}")
+message("Found  RVM   Ruby (${RVM_RUBY_VERSION}): ${MY_RUBY_HOME}/bin/ruby")
+
+add_test(NAME FindRuby.RvmDefault
+         COMMAND "${CMAKE_COMMAND}" -E env "MY_RUBY_HOME=${MY_RUBY_HOME}"
+                 "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/RvmDefault.cmake")
+
+add_test(NAME FindRuby.RvmOnly
+  COMMAND "${CMAKE_COMMAND}" -E env --unset=PATH
+                                    "MY_RUBY_HOME=${MY_RUBY_HOME}"
+          "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
+                 "-DRVM_RUBY_VERSION=${RVM_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/RvmOnly.cmake")
+add_test(NAME FindRuby.UnsetRvmOnly
+         COMMAND "${CMAKE_COMMAND}" -E env --unset=MY_RUBY_HOME "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
+                 "${CMAKE_COMMAND}" "-DRVM_RUBY_VERSION=${RVM_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/RvmOnly.cmake")
+
+add_test(NAME FindRuby.RvmStandard
+         COMMAND "${CMAKE_COMMAND}" -E env "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
+                                           "MY_RUBY_HOME=${MY_RUBY_HOME}"
+                 "${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
+                 -P "${CMAKE_CURRENT_LIST_DIR}/RvmStandard.cmake")
diff --git a/Tests/FindRuby/Rvm/RvmDefault.cmake b/Tests/FindRuby/Rvm/RvmDefault.cmake
new file mode 100644
index 0000000..a66b911
--- /dev/null
+++ b/Tests/FindRuby/Rvm/RvmDefault.cmake
@@ -0,0 +1,17 @@
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES "")
+
+find_package (Ruby 2.1.1 REQUIRED)
+if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
+  message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
+endif()
+
+find_package (Ruby 2.1 REQUIRED)
+if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
+  message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
+endif()
+
+find_package (Ruby REQUIRED)
+if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
+  message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
+endif()
diff --git a/Tests/FindRuby/Rvm/RvmOnly.cmake b/Tests/FindRuby/Rvm/RvmOnly.cmake
new file mode 100644
index 0000000..3851a7c
--- /dev/null
+++ b/Tests/FindRuby/Rvm/RvmOnly.cmake
@@ -0,0 +1,41 @@
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES "")
+
+set(Ruby_FIND_VIRTUALENV ONLY)
+
+# Test: FindRuby.RvmOnly
+if (RUBY_HOME)
+  # => Trying to find exactly system ruby using ONLY virtual environment should fail
+  find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
+  if(Ruby_FOUND)
+    message (FATAL_ERROR "Ruby unexpectedly found.")
+  endif()
+  # And should work to find the rvm version
+  find_package (Ruby ${RVM_RUBY_VERSION} EXACT QUIET)
+  if(Ruby_FOUND)
+    message (FATAL_ERROR "Ruby unexpectedly found.")
+  endif()
+endif()
+
+
+# Test: FindRuby.UnsetRvmOnly
+if (NOT RUBY_HOME)
+
+  # If ENV{MY_RUBY_HOME} isn't defined, it should default back to "STANDARD"
+  # At which point:
+
+  # It shouldn't find the RVM ruby
+  find_package (Ruby ${RVM_RUBY_VERSION} EXACT QUIET)
+  if(Ruby_FOUND)
+    message(FATAL_ERROR "Found RVM ruby when expecting system")
+  endif()
+
+  # it should find the system ruby
+  find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
+  if(NOT Ruby_FOUND)
+    message (FATAL_ERROR "Ruby not found.")
+  endif()
+  if (Ruby_FOUND MATCHES "^${RUBY_HOME}/.+")
+    message(FATAL_ERROR "Failed to find system ruby")
+  endif()
+endif()
diff --git a/Tests/FindRuby/Rvm/RvmStandard.cmake b/Tests/FindRuby/Rvm/RvmStandard.cmake
new file mode 100644
index 0000000..26befdb
--- /dev/null
+++ b/Tests/FindRuby/Rvm/RvmStandard.cmake
@@ -0,0 +1,9 @@
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES "")
+
+set (Ruby_FIND_VIRTUALENV STANDARD)
+find_package (Ruby REQUIRED)
+
+if (RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
+  message (FATAL_ERROR "RVM ruby unexpectedly found at ${RUBY_EXECUTABLE}, matches ${RUBY_HOME}")
+endif()
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 101e10c..2a4af3e 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -665,7 +665,7 @@
 
 add_RunCMake_test("CTestCommandExpandLists")
 
-add_RunCMake_test(PrecompileHeaders)
+add_RunCMake_test(PrecompileHeaders -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
 add_RunCMake_test("UnityBuild")
 
 add_RunCMake_test(cmake_command)
diff --git a/Tests/RunCMake/CTestTimeout/Basic-stdout.txt b/Tests/RunCMake/CTestTimeout/Basic-stdout.txt
index 30ed178..db59dbf 100644
--- a/Tests/RunCMake/CTestTimeout/Basic-stdout.txt
+++ b/Tests/RunCMake/CTestTimeout/Basic-stdout.txt
@@ -1,6 +1,6 @@
 Test project [^
 ]*/Tests/RunCMake/CTestTimeout/Basic-build
     Start 1: TestTimeout
-1/1 Test #1: TestTimeout ......................\*\*\*Timeout +[0-9.]+ sec
+1/1 Test #1: TestTimeout ......................\*\*\*Timeout +[1-9][0-9.]* sec
 +
 0% tests passed, 1 tests failed out of 1
diff --git a/Tests/RunCMake/CTestTimeout/Fork-stdout.txt b/Tests/RunCMake/CTestTimeout/Fork-stdout.txt
index 284e4b1..2938d8e 100644
--- a/Tests/RunCMake/CTestTimeout/Fork-stdout.txt
+++ b/Tests/RunCMake/CTestTimeout/Fork-stdout.txt
@@ -1,6 +1,6 @@
 Test project [^
 ]*/Tests/RunCMake/CTestTimeout/Fork-build
     Start 1: TestTimeout
-1/1 Test #1: TestTimeout ......................\*\*\*Timeout +[0-9.]+ sec
+1/1 Test #1: TestTimeout ......................\*\*\*Timeout +[1-9][0-9.]* sec
 +
 0% tests passed, 1 tests failed out of 1
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 41f13db..f95a6ee 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -673,12 +673,11 @@
   set(RunCMake_TEST_NO_CLEAN 1)
   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
-
   run_cmake_command(llvm_rc_no_args ${CMAKE_COMMAND} -E cmake_llvm_rc)
   run_cmake_command(llvm_rc_no_-- ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -E echo "This is a test")
   run_cmake_command(llvm_rc_empty_preprocessor ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp -- ${CMAKE_COMMAND} -E echo "This is a test")
-  run_cmake_command(llvm_rc_failing_first_command ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -E false -- ${CMAKE_COMMAND} -E echo "This is a test")
-  run_cmake_command(llvm_rc_failing_second_command ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -E echo "This is a test" -- ${CMAKE_COMMAND} -E false )
+  run_cmake_command(llvm_rc_failing_first_command ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -P FailedProgram.cmake -- ${CMAKE_COMMAND} -E echo "This is a test")
+  run_cmake_command(llvm_rc_failing_second_command ${CMAKE_COMMAND} -E cmake_llvm_rc test.tmp ${CMAKE_COMMAND} -E echo "This is a test" -- ${CMAKE_COMMAND} -P FailedProgram.cmake )
   if(EXISTS ${RunCMake_TEST_BINARY_DIR}/test.tmp)
       message(SEND_ERROR "${test} - FAILED:\n"
         "test.tmp was not deleted")
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_failing_first_command-stderr.txt b/Tests/RunCMake/CommandLine/llvm_rc_failing_first_command-stderr.txt
new file mode 100644
index 0000000..765b708
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_failing_first_command-stderr.txt
@@ -0,0 +1 @@
+CMake Error
diff --git a/Tests/RunCMake/CommandLine/llvm_rc_failing_second_command-stderr.txt b/Tests/RunCMake/CommandLine/llvm_rc_failing_second_command-stderr.txt
new file mode 100644
index 0000000..765b708
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/llvm_rc_failing_second_command-stderr.txt
@@ -0,0 +1 @@
+CMake Error
diff --git a/Tests/RunCMake/GenerateExportHeader/exportheader_test.cpp b/Tests/RunCMake/GenerateExportHeader/exportheader_test.cpp
index ba77679..dcaa4f2 100644
--- a/Tests/RunCMake/GenerateExportHeader/exportheader_test.cpp
+++ b/Tests/RunCMake/GenerateExportHeader/exportheader_test.cpp
@@ -32,14 +32,14 @@
     // trailing null to the string that we need to strip before testing for a
     // trailing space.
     if (refLine.size() && refLine[refLine.size() - 1] == 0) {
-      refLine = refLine.substr(0, refLine.size() - 1);
+      refLine.resize(refLine.size() - 1);
     }
     if (testLine.size() && testLine[testLine.size() - 1] == 0) {
-      testLine = testLine.substr(0, testLine.size() - 1);
+      testLine.resize(testLine.size() - 1);
     }
     // The reference files never have trailing spaces:
     if (testLine.size() && testLine[testLine.size() - 1] == ' ') {
-      testLine = testLine.substr(0, testLine.size() - 1);
+      testLine.resize(testLine.size() - 1);
     }
     if (refLine != testLine) {
       std::cout << "Ref and test are not the same:\n  Ref:  \"" << refLine
diff --git a/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid-check.cmake
new file mode 100644
index 0000000..3e7fb30
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid-check.cmake
@@ -0,0 +1,22 @@
+if (NOT CMAKE_C_COMPILER_ID MATCHES "GNU|Intel" OR
+   (CMAKE_C_COMPILER_ID STREQUAL "Intel" AND CMAKE_HOST_WIN32))
+  return()
+endif()
+
+file(STRINGS ${RunCMake_TEST_BINARY_DIR}/compile_commands.json empty_dir_commands
+     REGEX "command.*-Winvalid-pch.*empty.dir/cmake_pch.h")
+file(STRINGS ${RunCMake_TEST_BINARY_DIR}/compile_commands.json foo_dir_commands
+     REGEX "command.*-Winvalid-pch.*foo.dir/cmake_pch.h")
+
+list(LENGTH empty_dir_commands empty_dir_commands_size)
+list(LENGTH foo_dir_commands foo_dir_commands_size)
+
+if (empty_dir_commands_size EQUAL 0)
+  set(RunCMake_TEST_FAILED "empty target should have -Winvalid-pch compile option present")
+  return()
+endif()
+
+if (foo_dir_commands_size GREATER 0)
+  set(RunCMake_TEST_FAILED "foo target should not have -Winvalid-pch compile option present")
+  return()
+endif()
diff --git a/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid.cmake b/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid.cmake
new file mode 100644
index 0000000..4525664
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid.cmake
@@ -0,0 +1,16 @@
+enable_language(C)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+add_library(empty empty.c)
+target_precompile_headers(empty PUBLIC
+  <stdio.h>
+  <string.h>
+)
+
+add_library(foo foo.c)
+target_precompile_headers(foo PUBLIC
+  <stdio.h>
+  <string.h>
+)
+set_target_properties(foo PROPERTIES PCH_WARN_INVALID OFF)
diff --git a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
index f587c7d..3f684fc 100644
--- a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
@@ -21,3 +21,6 @@
 run_test(PchReuseFromPrefixed)
 run_test(PchReuseFromSubdir)
 run_cmake(PchMultilanguage)
+if(RunCMake_GENERATOR MATCHES "Make|Ninja")
+  run_cmake(PchWarnInvalid)
+endif()
diff --git a/Tests/RunCMake/export/Repeat-CMP0103-NEW-result.txt b/Tests/RunCMake/export/Repeat-CMP0103-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat-CMP0103-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/export/Repeat-CMP0103-NEW-stderr.txt b/Tests/RunCMake/export/Repeat-CMP0103-NEW-stderr.txt
new file mode 100644
index 0000000..48ab7b1
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat-CMP0103-NEW-stderr.txt
@@ -0,0 +1,17 @@
+CMake Error at Repeat.cmake:[0-9]+ \(export\):
+  export command already specified for the file
+
+    foo.cmake
+
+  Did you miss 'APPEND' keyword\?
+Call Stack \(most recent call first\):
+  Repeat-CMP0103-NEW.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)
+
+
+CMake Error at Repeat/CMakeLists.txt:[0-9]+ \(export\):
+  export command already specified for the file
+
+    .+/foo.cmake
+
+  Did you miss 'APPEND' keyword\?
diff --git a/Tests/RunCMake/export/Repeat-CMP0103-NEW.cmake b/Tests/RunCMake/export/Repeat-CMP0103-NEW.cmake
new file mode 100644
index 0000000..69381df
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat-CMP0103-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0103 NEW)
+include(Repeat.cmake)
diff --git a/Tests/RunCMake/export/Repeat-CMP0103-OLD.cmake b/Tests/RunCMake/export/Repeat-CMP0103-OLD.cmake
new file mode 100644
index 0000000..25134d6
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat-CMP0103-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0103 OLD)
+include(Repeat.cmake)
diff --git a/Tests/RunCMake/export/Repeat-CMP0103-WARN-stderr.txt b/Tests/RunCMake/export/Repeat-CMP0103-WARN-stderr.txt
new file mode 100644
index 0000000..3104df4
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat-CMP0103-WARN-stderr.txt
@@ -0,0 +1,26 @@
+CMake Warning \(dev\) at Repeat.cmake:[0-9]+ \(export\):
+  Policy CMP0103 is not set: multiple export\(\) with same FILE without APPEND
+  is not allowed.  Run "cmake --help-policy CMP0103" for policy details.  Use
+  the cmake_policy command to set the policy and suppress this warning.
+
+  export\(\) command already specified for the file
+
+    foo.cmake
+
+  Did you miss 'APPEND' keyword\?
+Call Stack \(most recent call first\):
+  Repeat-CMP0103-WARN.cmake:[0-9]+ \(include\)
+  CMakeLists.txt:[0-9]+ \(include\)
+This warning is for project developers.  Use -Wno-dev to suppress it.
+
+CMake Warning \(dev\) at Repeat/CMakeLists.txt:[0-9]+ \(export\):
+  Policy CMP0103 is not set: multiple export\(\) with same FILE without APPEND
+  is not allowed.  Run "cmake --help-policy CMP0103" for policy details.  Use
+  the cmake_policy command to set the policy and suppress this warning.
+
+  export\(\) command already specified for the file
+
+    .+/foo.cmake
+
+  Did you miss 'APPEND' keyword\?
+This warning is for project developers.  Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/export/Repeat-CMP0103-WARN.cmake b/Tests/RunCMake/export/Repeat-CMP0103-WARN.cmake
new file mode 100644
index 0000000..3a630c5
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat-CMP0103-WARN.cmake
@@ -0,0 +1 @@
+include(Repeat.cmake)
diff --git a/Tests/RunCMake/export/Repeat.cmake b/Tests/RunCMake/export/Repeat.cmake
new file mode 100644
index 0000000..f3262e7
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat.cmake
@@ -0,0 +1,5 @@
+add_library(foo INTERFACE)
+export(TARGETS foo FILE foo.cmake)
+export(TARGETS foo FILE foo.cmake)
+add_subdirectory(Repeat)
+include(CMakePackageConfigHelpers)
diff --git a/Tests/RunCMake/export/Repeat/CMakeLists.txt b/Tests/RunCMake/export/Repeat/CMakeLists.txt
new file mode 100644
index 0000000..b37f6ca
--- /dev/null
+++ b/Tests/RunCMake/export/Repeat/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(bar INTERFACE)
+export(TARGETS bar FILE ${CMAKE_BINARY_DIR}/foo.cmake)
diff --git a/Tests/RunCMake/export/RunCMakeTest.cmake b/Tests/RunCMake/export/RunCMakeTest.cmake
index 4d2f217..1c74762 100644
--- a/Tests/RunCMake/export/RunCMakeTest.cmake
+++ b/Tests/RunCMake/export/RunCMakeTest.cmake
@@ -2,6 +2,9 @@
 
 run_cmake(CustomTarget)
 run_cmake(Empty)
+run_cmake(Repeat-CMP0103-WARN)
+run_cmake(Repeat-CMP0103-OLD)
+run_cmake(Repeat-CMP0103-NEW)
 run_cmake(TargetNotFound)
 run_cmake(AppendExport)
 run_cmake(OldIface)
diff --git a/Utilities/std/CMakeLists.txt b/Utilities/std/CMakeLists.txt
index 63c0a60..a72abb7 100644
--- a/Utilities/std/CMakeLists.txt
+++ b/Utilities/std/CMakeLists.txt
@@ -1,4 +1,8 @@
 
+# To ensure maximum portability across various compilers and platforms
+# deactivate any compiler extensions
+set(CMAKE_CXX_EXTENSIONS FALSE)
+
 # source files for CMake std library
 set(SRCS cm/bits/string_view.cxx
          cm/memory