Merge topic 'better_gen_exp_example_tutotrial'

fa203ee323 Tutorial: Improve Step 10 generator expression example.

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !3571
diff --git a/Help/dev/maint.rst b/Help/dev/maint.rst
index 1153a09..37a1d3a 100644
--- a/Help/dev/maint.rst
+++ b/Help/dev/maint.rst
@@ -92,6 +92,45 @@
 .. _`CMake Review Process`: review.rst
 .. _`CMake CDash Page`: https://open.cdash.org/index.php?project=CMake
 
+Create Release Version
+======================
+
+When the ``release`` branch is ready to create a new release, follow the
+steps in the above `Maintain Current Release`_ section to checkout a local
+``release-$ver`` branch, where ``$ver`` is the version number of the
+current release in the form ``$major.$minor``.
+
+Edit ``Source/CMakeVersion.cmake`` to set the full version:
+
+.. code-block:: cmake
+
+  # CMake version number components.
+  set(CMake_VERSION_MAJOR $major)
+  set(CMake_VERSION_MINOR $minor)
+  set(CMake_VERSION_PATCH $patch)
+  #set(CMake_VERSION_RC $rc) # uncomment for release candidates
+
+In the following we use the placeholder ``$fullver`` for the full version
+number of the new release with the form ``$major.$minor.$patch[-rc$rc]``.
+If the version is not a release candidate, comment out the RC version
+component above and leave off the ``-rc$rc`` suffix from ``$fullver``.
+
+Commit the release version with the **exact** message ``CMake $fullver``:
+
+.. code-block:: shell
+
+  git commit -m "CMake $fullver"
+
+Tag the release using an annotated tag with the same message as the
+commit and named with the **exact** form ``v$fullver``:
+
+.. code-block:: shell
+
+  git tag -s -m "CMake $fullver" "v$fullver"
+
+Follow the steps in the above `Maintain Current Release`_ section to
+merge the ``release-$ver`` branch into ``master`` and publish both.
+
 Branch a New Release
 ====================
 
@@ -178,7 +217,7 @@
   the CMake Release Notes index page.
 
 Update ``Source/CMakeVersion.cmake`` to set the version to
-``$major.$minor.0-rc1``:
+``$major.$minor.0-rc0``:
 
 .. code-block:: cmake
 
@@ -186,7 +225,7 @@
   set(CMake_VERSION_MAJOR $major)
   set(CMake_VERSION_MINOR $minor)
   set(CMake_VERSION_PATCH 0)
-  set(CMake_VERSION_RC 1)
+  set(CMake_VERSION_RC 0)
 
 Update uses of ``DEVEL_CMAKE_VERSION`` in the source tree to mention the
 actual version number:
@@ -197,7 +236,7 @@
 
 Commit with a message such as::
 
-  CMake $major.$minor.0-rc1 version update
+  Begin $ver release versioning
 
 Merge the ``release-$ver`` branch to ``master``:
 
@@ -225,7 +264,7 @@
   set(CMake_VERSION_MAJOR $major)
   set(CMake_VERSION_MINOR $minor)
   set(CMake_VERSION_PATCH $date)
-  #set(CMake_VERSION_RC 1)
+  #set(CMake_VERSION_RC 0)
 
 Commit with a message such as::
 
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 6bdabaf..44ea1a8 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@
 .. toctree::
    :maxdepth: 1
 
+   CMP0097: ExternalProject_Add with GIT_SUBMODULES "" initializes no submodules. </policy/CMP0097>
    CMP0096: project() preserves leading zeros in version components. </policy/CMP0096>
    CMP0095: RPATH entries are properly escaped in the intermediary CMake install script. </policy/CMP0095>
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index ae4be3e..62d23c7 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -228,6 +228,7 @@
    /prop_tgt/IMPORT_SUFFIX
    /prop_tgt/INCLUDE_DIRECTORIES
    /prop_tgt/INSTALL_NAME_DIR
+   /prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH
    /prop_tgt/INSTALL_RPATH
    /prop_tgt/INSTALL_RPATH_USE_LINK_PATH
    /prop_tgt/INTERFACE_AUTOUIC_OPTIONS
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index 7435d9a..f233d08 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -399,8 +399,10 @@
   be false unless using a NDK that does not provide unified headers.
 
 :variable:`CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION`
-  Set to the version of the NDK toolchain to be selected as the compiler.
-  If not specified, the default will be the latest available GCC toolchain.
+  On NDK r19 or above, this variable must be unset or set to ``clang``.
+  On NDK r18 or below, set this to the version of the NDK toolchain to
+  be selected as the compiler.  If not specified, the default will be
+  the latest available GCC toolchain.
 
 :variable:`CMAKE_ANDROID_STL_TYPE`
   Set to specify which C++ standard library to use.  If not specified,
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index c3f6f8a..432d7fc 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -372,6 +372,7 @@
    /variable/CMAKE_INCLUDE_CURRENT_DIR
    /variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE
    /variable/CMAKE_INSTALL_NAME_DIR
+   /variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH
    /variable/CMAKE_INSTALL_RPATH
    /variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH
    /variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION
diff --git a/Help/policy/CMP0097.rst b/Help/policy/CMP0097.rst
new file mode 100644
index 0000000..8a5ff88
--- /dev/null
+++ b/Help/policy/CMP0097.rst
@@ -0,0 +1,23 @@
+CMP0097
+-------
+
+:command:`ExternalProject_Add` with ``GIT_SUBMODULES ""`` initializes no
+submodules.
+
+The module provides a ``GIT_SUBMODULES`` option which controls what submodules
+to initialize and update. Starting with CMake 3.16, explicitly setting
+``GIT_SUBMODULES`` to an empty string means no submodules will be initialized
+or updated.
+
+This policy provides compatibility for projects that have not been updated
+to expect the new behavior.
+
+The ``OLD`` behavior for this policy is for ``GIT_SUBMODULES`` when set to
+an empty string to initialize and update all git submodules.
+The ``New`` behavior for this policy is for ``GIT_SUBMODULES`` when set to
+an empty string to initialize and update no git submodules.
+
+This policy was introduced in CMake version 3.16.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+Unlike most policies, CMake version |release| does *not* warn
+when this policy is not set and simply uses ``OLD`` behavior.
diff --git a/Help/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH.rst b/Help/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH.rst
new file mode 100644
index 0000000..a474fc6
--- /dev/null
+++ b/Help/prop_tgt/INSTALL_REMOVE_ENVIRONMENT_RPATH.rst
@@ -0,0 +1,10 @@
+INSTALL_REMOVE_ENVIRONMENT_RPATH
+--------------------------------
+
+Removes compiler defined rpaths durimg installation.
+
+``INSTALL_REMOVE_ENVIRONMENT_RPATH`` is a boolean that if set to ``True`` will
+remove compiler defined rpaths from the project if the user also defines rpath
+with :prop_tgt:`INSTALL_RPATH`.  This property is initialized by whether the
+value of :variable:`CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH` is set when a
+target is created.
diff --git a/Help/release/3.15.rst b/Help/release/3.15.rst
index 2cff419..4f53466 100644
--- a/Help/release/3.15.rst
+++ b/Help/release/3.15.rst
@@ -345,3 +345,20 @@
 * The :command:`file(REMOVE)` and :command:`file(REMOVE_RECURSE)` commands
   were changed to ignore empty arguments with a warning instead of treating
   them as a relative path and removing the contents of the current directory.
+
+Updates
+=======
+
+Changes made since CMake 3.15.0 include the following.
+
+3.15.1
+------
+
+* In CMake 3.15.0 support for the GNU-like ``Clang`` compiler targeting the
+  MSVC ABI implemented :variable:`CMAKE_CXX_STANDARD` values 98 and 11 using
+  the corresponding ``-std=`` flags.  However, these modes do not work with
+  the MSVC standard library.  Therefore CMake 3.15.1 passes C++14 standard
+  flags even for C++98 and C++11.  This is consistent with MSVC itself which
+  always runs in a mode aware of C++14.
+
+* Preliminary Swift support added in 3.15.0 has been updated.
diff --git a/Help/release/dev/add-install-remove-environment-rpath.rst b/Help/release/dev/add-install-remove-environment-rpath.rst
new file mode 100644
index 0000000..156106c
--- /dev/null
+++ b/Help/release/dev/add-install-remove-environment-rpath.rst
@@ -0,0 +1,6 @@
+add-install-remove-environment-rpath
+------------------------------------
+
+* A new target property, :prop_tgt:`INSTALL_REMOVE_ENVIRONMENT_RPATH`, was
+  added which removes compiler-defined rpaths from a target. This property is
+  initialized by :variable:`CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH`.
diff --git a/Help/release/dev/external-project-support-no-git-submodules.rst b/Help/release/dev/external-project-support-no-git-submodules.rst
new file mode 100644
index 0000000..1d4be66
--- /dev/null
+++ b/Help/release/dev/external-project-support-no-git-submodules.rst
@@ -0,0 +1,6 @@
+external-project-support-no-git-submodules
+------------------------------------------
+
+* The :module:`ExternalProject` module's ``ExternalProject_Add`` command
+  has been updated so that ``GIT_SUBMODULES ""`` initializes no submodules. See
+  policy :policy:`CMP0097`.
diff --git a/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst b/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst
index 5ae55d1..22808e3 100644
--- a/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst
+++ b/Help/variable/CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION.rst
@@ -3,7 +3,11 @@
 
 When :ref:`Cross Compiling for Android with the NDK`, this variable
 may be set to specify the version of the toolchain to be used
-as the compiler.  The variable must be set to one of these forms:
+as the compiler.
+
+On NDK r19 or above, this variable must be unset or set to ``clang``.
+
+On NDK r18 or below, this variable must be set to one of these forms:
 
 * ``<major>.<minor>``: GCC of specified version
 * ``clang<major>.<minor>``: Clang of specified version
diff --git a/Help/variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH.rst b/Help/variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH.rst
new file mode 100644
index 0000000..19ae5f3
--- /dev/null
+++ b/Help/variable/CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH.rst
@@ -0,0 +1,9 @@
+CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH
+--------------------------------------
+
+Removes compiler defined rpaths durimg installation.
+
+``CMAKE_INSTALL_REMOVE_ENVIRONMENT_RPATH`` is a boolean that if set to ``true``
+removes compiler defined rpaths from the project if the user also defines rpath
+with :prop_tgt:`INSTALL_RPATH`. This is used to initialize the target property
+:prop_tgt:`INSTALL_REMOVE_ENVIRONMENT_RPATH` for all targets.
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 20b37d2..14fc231 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -261,7 +261,9 @@
 
       ``GIT_SUBMODULES <module>...``
         Specific git submodules that should also be updated. If this option is
-        not provided, all git submodules will be updated.
+        not provided, all git submodules will be updated. When :policy:`CMP0097`
+        is set to ``NEW`` if this value is set to an empty string then no submodules
+        are initialized or updated.
 
       ``GIT_SHALLOW <bool>``
         When this option is enabled, the ``git clone`` operation will be given
@@ -1016,6 +1018,9 @@
       endif()
     else()
       set(key "${arg}")
+      if(key MATCHES GIT)
+       get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
+      endif()
     endif()
   endforeach()
 endfunction()
@@ -1060,7 +1065,7 @@
   "ExternalProject module."
   )
 
-function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify)
+function(_ep_write_gitclone_script script_filename source_dir git_EXECUTABLE git_repository git_tag git_remote_name init_submodules git_submodules git_shallow git_progress git_config src_name work_dir gitclone_infofile gitclone_stampfile tls_verify)
   if(NOT GIT_VERSION_STRING VERSION_LESS 1.8.5)
     # Use `git checkout <tree-ish> --` to avoid ambiguity with a local path.
     set(git_checkout_explicit-- "--")
@@ -1145,11 +1150,14 @@
   message(FATAL_ERROR \"Failed to checkout tag: '${git_tag}'\")
 endif()
 
-execute_process(
-  COMMAND \"${git_EXECUTABLE}\" ${git_options} submodule update --recursive --init ${git_submodules}
-  WORKING_DIRECTORY \"${work_dir}/${src_name}\"
-  RESULT_VARIABLE error_code
-  )
+set(init_submodules ${init_submodules})
+if(init_submodules)
+  execute_process(
+    COMMAND \"${git_EXECUTABLE}\" ${git_options} submodule update --recursive --init ${git_submodules}
+    WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+    RESULT_VARIABLE error_code
+    )
+endif()
 if(error_code)
   message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
 endif()
@@ -1226,7 +1234,7 @@
 endfunction()
 
 
-function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name git_submodules git_repository work_dir)
+function(_ep_write_gitupdate_script script_filename git_EXECUTABLE git_tag git_remote_name init_submodules git_submodules git_repository work_dir)
   if("${git_tag}" STREQUAL "")
     message(FATAL_ERROR "Tag for git checkout should not be empty.")
   endif()
@@ -1383,11 +1391,14 @@
     endif()
   endif()
 
-  execute_process(
-    COMMAND \"${git_EXECUTABLE}\" submodule update --recursive --init ${git_submodules}
-    WORKING_DIRECTORY \"${work_dir}/${src_name}\"
-    RESULT_VARIABLE error_code
-    )
+  set(init_submodules ${init_submodules})
+  if(init_submodules)
+    execute_process(
+      COMMAND \"${git_EXECUTABLE}\" submodule update --recursive --init ${git_submodules}
+      WORKING_DIRECTORY \"${work_dir}/${src_name}\"
+      RESULT_VARIABLE error_code
+      )
+  endif()
   if(error_code)
     message(FATAL_ERROR \"Failed to update submodules in: '${work_dir}/${src_name}'\")
   endif()
@@ -1972,7 +1983,7 @@
     set(stderr_log "${logbase}-err.log")
   endif()
   set(code "
-cmake_minimum_required(VERSION 3.13)
+cmake_minimum_required(VERSION 3.15)
 ${code_cygpath_make}
 set(command \"${command}\")
 set(log_merged \"${log_merged}\")
@@ -2420,7 +2431,15 @@
     if(NOT git_tag)
       set(git_tag "master")
     endif()
-    get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
+
+    set(git_init_submodules TRUE)
+    get_property(git_submodules_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES SET)
+    if(git_submodules_set)
+      get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
+      if(git_submodules  STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
+        set(git_init_submodules FALSE)
+      endif()
+    endif()
 
     get_property(git_remote_name TARGET ${name} PROPERTY _EP_GIT_REMOTE_NAME)
     if(NOT git_remote_name)
@@ -2458,7 +2477,7 @@
     # The script will delete the source directory and then call git clone.
     #
     _ep_write_gitclone_script(${tmp_dir}/${name}-gitclone.cmake ${source_dir}
-      ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${git_remote_name} "${git_submodules}" "${git_shallow}" "${git_progress}" "${git_config}" ${src_name} ${work_dir}
+      ${GIT_EXECUTABLE} ${git_repository} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules}" "${git_shallow}" "${git_progress}" "${git_config}" ${src_name} ${work_dir}
       ${stamp_dir}/${name}-gitinfo.txt ${stamp_dir}/${name}-gitclone-lastrun.txt "${tls_verify}"
       )
     set(comment "Performing download step (git clone) for '${name}'")
@@ -2723,9 +2742,18 @@
     if(NOT git_remote_name)
       set(git_remote_name "origin")
     endif()
-    get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
+
+    set(git_init_submodules TRUE)
+    get_property(git_submodules_set TARGET ${name} PROPERTY _EP_GIT_SUBMODULES SET)
+    if(git_submodules_set)
+      get_property(git_submodules TARGET ${name} PROPERTY _EP_GIT_SUBMODULES)
+      if(git_submodules  STREQUAL "" AND _EP_CMP0097 STREQUAL "NEW")
+        set(git_init_submodules FALSE)
+      endif()
+    endif()
+
     _ep_write_gitupdate_script(${tmp_dir}/${name}-gitupdate.cmake
-      ${GIT_EXECUTABLE} ${git_tag} ${git_remote_name} "${git_submodules}" ${git_repository} ${work_dir}
+      ${GIT_EXECUTABLE} ${git_tag} ${git_remote_name} ${git_init_submodules} "${git_submodules}" ${git_repository} ${work_dir}
       )
     set(cmd ${CMAKE_COMMAND} -P ${tmp_dir}/${name}-gitupdate.cmake)
     set(always 1)
@@ -3138,6 +3166,10 @@
 
 
 function(ExternalProject_Add name)
+  cmake_policy(GET CMP0097 _EP_CMP0097
+    PARENT_SCOPE # undocumented, do not use outside of CMake
+    )
+
   _ep_get_configuration_subdir_suffix(cfgdir)
 
   # Add a custom target for the external project.
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake
index 2ff6afe..a79758f 100644
--- a/Modules/FindMPI.cmake
+++ b/Modules/FindMPI.cmake
@@ -1147,9 +1147,7 @@
   set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_COMPILE_DEFINITIONS "${MPI_${LANG}_COMPILE_DEFINITIONS}")
 
   if(MPI_${LANG}_LINK_FLAGS)
-    separate_arguments(_MPI_${LANG}_LINK_FLAGS NATIVE_COMMAND "${MPI_${LANG}_LINK_FLAGS}")
-    set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_LINK_OPTIONS "${_MPI_${LANG}_LINK_FLAGS}")
-    unset(_MPI_${LANG}_LINK_FLAGS)
+    set_property(TARGET MPI::MPI_${LANG} PROPERTY INTERFACE_LINK_OPTIONS "SHELL:${MPI_${LANG}_LINK_FLAGS}")
   endif()
   # If the compiler links MPI implicitly, no libraries will be found as they're contained within
   # CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES already.
diff --git a/Modules/Platform/Android-Clang.cmake b/Modules/Platform/Android-Clang.cmake
index 9ed1e01..847178f 100644
--- a/Modules/Platform/Android-Clang.cmake
+++ b/Modules/Platform/Android-Clang.cmake
@@ -40,6 +40,9 @@
   endif()
   if(NOT CMAKE_${lang}_COMPILER_TARGET)
     set(CMAKE_${lang}_COMPILER_TARGET "${_ANDROID_ABI_CLANG_TARGET}")
+    if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+      string(APPEND CMAKE_${lang}_COMPILER_TARGET "${CMAKE_SYSTEM_VERSION}")
+    endif()
     list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "--target=${CMAKE_${lang}_COMPILER_TARGET}")
   endif()
 endmacro()
diff --git a/Modules/Platform/Android-Common.cmake b/Modules/Platform/Android-Common.cmake
index f8b9346..1affcd0 100644
--- a/Modules/Platform/Android-Common.cmake
+++ b/Modules/Platform/Android-Common.cmake
@@ -47,7 +47,41 @@
 endif()
 
 if(CMAKE_ANDROID_STL_TYPE)
-  if(CMAKE_ANDROID_NDK)
+  if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+    if(CMAKE_ANDROID_STL_TYPE STREQUAL "system")
+      set(_ANDROID_STL_EXCEPTIONS 0)
+      set(_ANDROID_STL_RTTI 0)
+      macro(__android_stl lang)
+        string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libstdc++")
+      endmacro()
+    elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_static")
+      set(_ANDROID_STL_EXCEPTIONS 1)
+      set(_ANDROID_STL_RTTI 1)
+      macro(__android_stl lang)
+        string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libc++")
+        string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -static-libstdc++")
+      endmacro()
+    elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_shared")
+      set(_ANDROID_STL_EXCEPTIONS 1)
+      set(_ANDROID_STL_RTTI 1)
+      macro(__android_stl lang)
+        string(APPEND CMAKE_${lang}_FLAGS_INIT " -stdlib=libc++")
+      endmacro()
+    elseif(CMAKE_ANDROID_STL_TYPE STREQUAL "none")
+      set(_ANDROID_STL_RTTI 0)
+      set(_ANDROID_STL_EXCEPTIONS 0)
+      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++")
+        string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -nostdlib++")
+      endmacro()
+    else()
+      message(FATAL_ERROR
+        "Android: STL '${CMAKE_ANDROID_STL_TYPE}' not supported by this NDK."
+        )
+    endif()
+  elseif(CMAKE_ANDROID_NDK)
 
     macro(__android_stl_inc lang dir req)
       if(EXISTS "${dir}")
@@ -152,6 +186,10 @@
     __android_stl(CXX)
   endif()
 
+  if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+    string(APPEND CMAKE_${lang}_STANDARD_LIBRARIES " -latomic -lm")
+  endif()
+
   # <ndk>/build/core/definitions.mk appends the sysroot's include directory
   # explicitly at the end of the command-line include path so that it
   # precedes the toolchain's builtin include directories.  This is
@@ -161,7 +199,7 @@
   #
   # Do not do this for a standalone toolchain because it is already
   # tied to a specific API version.
-  if(CMAKE_ANDROID_NDK)
+  if(CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
     if(CMAKE_SYSROOT_COMPILE)
       set(_cmake_sysroot_compile "${CMAKE_SYSROOT_COMPILE}")
     else()
@@ -170,7 +208,7 @@
     if(NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
       list(APPEND CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES
         "${_cmake_sysroot_compile}/usr/include"
-        "${_cmake_sysroot_compile}/usr/include/${CMAKE_ANDROID_ARCH_HEADER_TRIPLE}"
+        "${_cmake_sysroot_compile}/usr/include/${CMAKE_ANDROID_ARCH_TRIPLE}"
         )
     else()
       list(APPEND CMAKE_${lang}_STANDARD_INCLUDE_DIRECTORIES "${_cmake_sysroot_compile}/usr/include")
diff --git a/Modules/Platform/Android-Determine.cmake b/Modules/Platform/Android-Determine.cmake
index bb42eed..e7c1b48 100644
--- a/Modules/Platform/Android-Determine.cmake
+++ b/Modules/Platform/Android-Determine.cmake
@@ -198,32 +198,66 @@
   message(FATAL_ERROR "Android: The API specified by CMAKE_SYSTEM_VERSION='${CMAKE_SYSTEM_VERSION}' is not an integer.")
 endif()
 
+if(CMAKE_ANDROID_NDK)
+  # Identify the host platform.
+  if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
+    if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
+      set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "darwin-x86_64")
+    else()
+      set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "darwin-x86")
+    endif()
+  elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
+    if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
+      set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "linux-x86_64")
+    else()
+      set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "linux-x86")
+    endif()
+  elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
+    if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64")
+      set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "windows-x86_64")
+    else()
+      set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "windows")
+    endif()
+  else()
+    message(FATAL_ERROR "Android: Builds hosted on '${CMAKE_HOST_SYSTEM_NAME}' not supported.")
+  endif()
+
+  # Look for a unified toolchain/sysroot provided with the NDK.
+  set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "${CMAKE_ANDROID_NDK}/toolchains/llvm/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}")
+  if(NOT IS_DIRECTORY "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/sysroot")
+    set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "")
+  endif()
+else()
+  set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG "")
+  set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED "")
+endif()
+
 # https://developer.android.com/ndk/guides/abis.html
 
 set(_ANDROID_ABI_arm64-v8a_PROC     "aarch64")
 set(_ANDROID_ABI_arm64-v8a_ARCH     "arm64")
-set(_ANDROID_ABI_arm64-v8a_HEADER   "aarch64-linux-android")
+set(_ANDROID_ABI_arm64-v8a_TRIPLE   "aarch64-linux-android")
 set(_ANDROID_ABI_armeabi-v7a_PROC   "armv7-a")
 set(_ANDROID_ABI_armeabi-v7a_ARCH   "arm")
-set(_ANDROID_ABI_armeabi-v7a_HEADER "arm-linux-androideabi")
+set(_ANDROID_ABI_armeabi-v7a_TRIPLE "arm-linux-androideabi")
 set(_ANDROID_ABI_armeabi-v6_PROC    "armv6")
 set(_ANDROID_ABI_armeabi-v6_ARCH    "arm")
-set(_ANDROID_ABI_armeabi-v6_HEADER  "arm-linux-androideabi")
+set(_ANDROID_ABI_armeabi-v6_TRIPLE  "arm-linux-androideabi")
 set(_ANDROID_ABI_armeabi_PROC       "armv5te")
 set(_ANDROID_ABI_armeabi_ARCH       "arm")
-set(_ANDROID_ABI_armeabi_HEADER     "arm-linux-androideabi")
+set(_ANDROID_ABI_armeabi_TRIPLE     "arm-linux-androideabi")
 set(_ANDROID_ABI_mips_PROC          "mips")
 set(_ANDROID_ABI_mips_ARCH          "mips")
-set(_ANDROID_ABI_mips_HEADER        "mipsel-linux-android")
+set(_ANDROID_ABI_mips_TRIPLE        "mipsel-linux-android")
 set(_ANDROID_ABI_mips64_PROC        "mips64")
 set(_ANDROID_ABI_mips64_ARCH        "mips64")
-set(_ANDROID_ABI_mips64_HEADER      "mips64el-linux-android")
+set(_ANDROID_ABI_mips64_TRIPLE      "mips64el-linux-android")
 set(_ANDROID_ABI_x86_PROC           "i686")
 set(_ANDROID_ABI_x86_ARCH           "x86")
-set(_ANDROID_ABI_x86_HEADER         "i686-linux-android")
+set(_ANDROID_ABI_x86_TRIPLE         "i686-linux-android")
 set(_ANDROID_ABI_x86_64_PROC        "x86_64")
 set(_ANDROID_ABI_x86_64_ARCH        "x86_64")
-set(_ANDROID_ABI_x86_64_HEADER      "x86_64-linux-android")
+set(_ANDROID_ABI_x86_64_TRIPLE      "x86_64-linux-android")
 
 set(_ANDROID_PROC_aarch64_ARCH_ABI "arm64-v8a")
 set(_ANDROID_PROC_armv7-a_ARCH_ABI "armeabi-v7a")
@@ -308,7 +342,7 @@
     "does not match architecture '${CMAKE_ANDROID_ARCH}' for the ABI '${CMAKE_ANDROID_ARCH_ABI}'."
     )
 endif()
-set(CMAKE_ANDROID_ARCH_HEADER_TRIPLE "${_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_HEADER}")
+set(CMAKE_ANDROID_ARCH_TRIPLE "${_ANDROID_ABI_${CMAKE_ANDROID_ARCH_ABI}_TRIPLE}")
 
 # Select a processor.
 if(NOT CMAKE_SYSTEM_PROCESSOR)
@@ -321,7 +355,7 @@
 endif()
 
 if(CMAKE_ANDROID_NDK AND NOT DEFINED CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
-  if(IS_DIRECTORY "${CMAKE_ANDROID_NDK}/sysroot/usr/include/${CMAKE_ANDROID_ARCH_HEADER_TRIPLE}")
+  if(IS_DIRECTORY "${CMAKE_ANDROID_NDK}/sysroot/usr/include/${CMAKE_ANDROID_ARCH_TRIPLE}")
     # Unified headers exist so we use them by default.
     set(CMAKE_ANDROID_NDK_DEPRECATED_HEADERS 0)
   else()
@@ -340,8 +374,10 @@
 
 if(CMAKE_ANDROID_NDK)
   string(APPEND CMAKE_SYSTEM_CUSTOM_CODE
-    "set(CMAKE_ANDROID_ARCH_HEADER_TRIPLE \"${CMAKE_ANDROID_ARCH_HEADER_TRIPLE}\")\n"
+    "set(CMAKE_ANDROID_ARCH_TRIPLE \"${CMAKE_ANDROID_ARCH_TRIPLE}\")\n"
     "set(CMAKE_ANDROID_NDK_DEPRECATED_HEADERS \"${CMAKE_ANDROID_NDK_DEPRECATED_HEADERS}\")\n"
+    "set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG \"${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}\")\n"
+    "set(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED \"${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}\")\n"
     )
 endif()
 
diff --git a/Modules/Platform/Android-Initialize.cmake b/Modules/Platform/Android-Initialize.cmake
index a434f90..a5d2820 100644
--- a/Modules/Platform/Android-Initialize.cmake
+++ b/Modules/Platform/Android-Initialize.cmake
@@ -17,6 +17,13 @@
   return()
 endif()
 
+set(CMAKE_BUILD_TYPE_INIT Debug)
+
+# Skip sysroot selection if the NDK has a unified toolchain.
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+  return()
+endif()
+
 if(NOT CMAKE_SYSROOT)
   if(CMAKE_ANDROID_NDK)
     set(CMAKE_SYSROOT "${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}")
@@ -40,5 +47,3 @@
     "Android: No CMAKE_SYSROOT was selected."
     )
 endif()
-
-set(CMAKE_BUILD_TYPE_INIT Debug)
diff --git a/Modules/Platform/Android/Determine-Compiler-NDK.cmake b/Modules/Platform/Android/Determine-Compiler-NDK.cmake
index 5f2cc52..e009c10 100644
--- a/Modules/Platform/Android/Determine-Compiler-NDK.cmake
+++ b/Modules/Platform/Android/Determine-Compiler-NDK.cmake
@@ -1,6 +1,31 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
+# In Android NDK r19 and above there is a single clang toolchain.
+if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED)
+  if(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION STREQUAL "clang")
+    message(FATAL_ERROR
+      "Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}' "
+      "is not supported by this NDK.  It must be 'clang' or not set at all."
+      )
+  endif()
+  message(STATUS "Android: Selected unified Clang toolchain")
+  set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "clang")
+  set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/clang${_ANDROID_HOST_EXT}")
+  set(_ANDROID_TOOL_C_TOOLCHAIN_MACHINE "${CMAKE_ANDROID_ARCH_TRIPLE}")
+  set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "")
+  set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN "")
+  set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/${CMAKE_ANDROID_ARCH_TRIPLE}-")
+  set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
+  set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/clang++${_ANDROID_HOST_EXT}")
+  set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "${CMAKE_ANDROID_ARCH_TRIPLE}")
+  set(_ANDROID_TOOL_CXX_TOOLCHAIN_VERSION "")
+  set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "")
+  set(_ANDROID_TOOL_CXX_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin/${CMAKE_ANDROID_ARCH_TRIPLE}-")
+  set(_ANDROID_TOOL_CXX_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
+  return()
+endif()
+
 # In Android NDK releases there is build system toolchain selection logic in
 # these files:
 #
@@ -195,40 +220,16 @@
   set(_ANDROID_TOOL_PREFIX "${CMAKE_MATCH_1}")
 endif()
 
-# Identify the host platform.
-if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
-  if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
-    set(_ANDROID_HOST_DIR "darwin-x86_64")
-  else()
-    set(_ANDROID_HOST_DIR "darwin-x86")
-  endif()
-elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
-  if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
-    set(_ANDROID_HOST_DIR "linux-x86_64")
-  else()
-    set(_ANDROID_HOST_DIR "linux-x86")
-  endif()
-elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
-  if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64")
-    set(_ANDROID_HOST_DIR "windows-x86_64")
-  else()
-    set(_ANDROID_HOST_DIR "windows")
-  endif()
-else()
-  message(FATAL_ERROR "Android: Builds hosted on '${CMAKE_HOST_SYSTEM_NAME}' not supported.")
-endif()
-
 # Help CMakeFindBinUtils locate things.
 set(_CMAKE_TOOLCHAIN_PREFIX "${_ANDROID_TOOL_PREFIX}")
 
-set(_ANDROID_TOOL_NDK_TOOLCHAIN_HOST_TAG "${_ANDROID_HOST_DIR}")
 set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "${_ANDROID_TOOL_VERS_NDK}")
 
 # _ANDROID_TOOL_PREFIX should now match `gcc -dumpmachine`.
 string(REGEX REPLACE "-$" "" _ANDROID_TOOL_C_TOOLCHAIN_MACHINE "${_ANDROID_TOOL_PREFIX}")
 
 set(_ANDROID_TOOL_C_TOOLCHAIN_VERSION "${_ANDROID_TOOL_VERS}")
-set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${_ANDROID_HOST_DIR}/bin/${_ANDROID_TOOL_PREFIX}")
+set(_ANDROID_TOOL_C_TOOLCHAIN_PREFIX "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/${_ANDROID_TOOL_PREFIX}")
 set(_ANDROID_TOOL_C_TOOLCHAIN_SUFFIX "${_ANDROID_HOST_EXT}")
 
 set(_ANDROID_TOOL_CXX_TOOLCHAIN_MACHINE "${_ANDROID_TOOL_C_TOOLCHAIN_MACHINE}")
@@ -238,9 +239,9 @@
 
 if(_ANDROID_TOOL_CLANG_NAME)
   message(STATUS "Android: Selected Clang toolchain '${_ANDROID_TOOL_CLANG_NAME}' with GCC toolchain '${_ANDROID_TOOL_NAME}'")
-  set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${_ANDROID_HOST_DIR}/bin/clang${_ANDROID_HOST_EXT}")
-  set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN ${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${_ANDROID_HOST_DIR})
-  set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${_ANDROID_HOST_DIR}/bin/clang++${_ANDROID_HOST_EXT}")
+  set(_ANDROID_TOOL_C_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/clang${_ANDROID_HOST_EXT}")
+  set(_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN ${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG})
+  set(_ANDROID_TOOL_CXX_COMPILER "${CMAKE_ANDROID_NDK}/toolchains/${_ANDROID_TOOL_LLVM_NAME}/prebuilt/${CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG}/bin/clang++${_ANDROID_HOST_EXT}")
   set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${_ANDROID_TOOL_C_COMPILER_EXTERNAL_TOOLCHAIN}")
 else()
   message(STATUS "Android: Selected GCC toolchain '${_ANDROID_TOOL_NAME}'")
@@ -267,4 +268,3 @@
 unset(_ANDROID_TOOL_CLANG_NAME)
 unset(_ANDROID_TOOL_CLANG_VERS)
 unset(_ANDROID_TOOL_LLVM_NAME)
-unset(_ANDROID_HOST_DIR)
diff --git a/Modules/Platform/Android/Determine-Compiler-Standalone.cmake b/Modules/Platform/Android/Determine-Compiler-Standalone.cmake
index 4c1ac1f..5095aff 100644
--- a/Modules/Platform/Android/Determine-Compiler-Standalone.cmake
+++ b/Modules/Platform/Android/Determine-Compiler-Standalone.cmake
@@ -62,5 +62,4 @@
   set(_ANDROID_TOOL_CXX_COMPILER_EXTERNAL_TOOLCHAIN "")
 endif()
 
-set(_ANDROID_TOOL_NDK_TOOLCHAIN_HOST_TAG "")
 set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "")
diff --git a/Modules/Platform/Android/Determine-Compiler.cmake b/Modules/Platform/Android/Determine-Compiler.cmake
index a03ebcc..5c6b97b 100644
--- a/Modules/Platform/Android/Determine-Compiler.cmake
+++ b/Modules/Platform/Android/Determine-Compiler.cmake
@@ -40,7 +40,6 @@
 elseif(CMAKE_ANDROID_STANDALONE_TOOLCHAIN)
   include(Platform/Android/Determine-Compiler-Standalone)
 else()
-  set(_ANDROID_TOOL_NDK_TOOLCHAIN_HOST_TAG "")
   set(_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION "")
   set(_ANDROID_TOOL_C_COMPILER "")
   set(_ANDROID_TOOL_C_TOOLCHAIN_MACHINE "")
@@ -65,7 +64,6 @@
 
     # Save the Android-specific information in CMake${lang}Compiler.cmake.
     set(CMAKE_${lang}_COMPILER_CUSTOM_CODE "
-set(CMAKE_ANDROID_NDK_TOOLCHAIN_HOST_TAG \"${_ANDROID_TOOL_NDK_TOOLCHAIN_HOST_TAG}\")
 set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION \"${_ANDROID_TOOL_NDK_TOOLCHAIN_VERSION}\")
 set(CMAKE_${lang}_ANDROID_TOOLCHAIN_MACHINE \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_MACHINE}\")
 set(CMAKE_${lang}_ANDROID_TOOLCHAIN_VERSION \"${_ANDROID_TOOL_${lang}_TOOLCHAIN_VERSION}\")
diff --git a/Modules/Platform/Android/abi-common.cmake b/Modules/Platform/Android/abi-common.cmake
index 6bce3c7..b01ef61 100644
--- a/Modules/Platform/Android/abi-common.cmake
+++ b/Modules/Platform/Android/abi-common.cmake
@@ -3,7 +3,7 @@
   " -no-canonical-prefixes"
   )
 
-if(CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
+if(CMAKE_ANDROID_NDK AND NOT CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED AND NOT CMAKE_ANDROID_NDK_DEPRECATED_HEADERS)
   string(APPEND _ANDROID_ABI_INIT_CFLAGS " -D__ANDROID_API__=${CMAKE_SYSTEM_VERSION}")
 endif()
 
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index f4875fb..bbf8be0 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 15)
-set(CMake_VERSION_PATCH 20190725)
-#set(CMake_VERSION_RC 1)
+set(CMake_VERSION_PATCH 20190729)
+#set(CMake_VERSION_RC 0)
diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake
index 72a5800..160f470 100644
--- a/Source/CMakeVersionCompute.cmake
+++ b/Source/CMakeVersionCompute.cmake
@@ -16,7 +16,7 @@
 set(CMake_VERSION ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH})
 if(CMake_VERSION_SOURCE)
   set(CMake_VERSION_SUFFIX "${CMake_VERSION_SOURCE}")
-elseif(CMake_VERSION_RC)
+elseif(DEFINED CMake_VERSION_RC)
   set(CMake_VERSION_SUFFIX "rc${CMake_VERSION_RC}")
 else()
   set(CMake_VERSION_SUFFIX "")
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
index 350ebed..512ac7a 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -759,7 +759,7 @@
     if (this->GetOption("CPACK_INSTALL_PREFIX")) {
       dir += this->GetOption("CPACK_INSTALL_PREFIX");
     }
-    mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir.c_str());
+    mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir);
 
     cmCPackLogger(
       cmCPackLog::LOG_DEBUG,
@@ -799,7 +799,7 @@
       return 0;
     }
   } else {
-    mf.AddDefinition("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str());
+    mf.AddDefinition("CMAKE_INSTALL_PREFIX", tempInstallDirectory);
 
     if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory,
                                            default_dir_mode)) {
@@ -818,11 +818,11 @@
   }
 
   if (!buildConfig.empty()) {
-    mf.AddDefinition("BUILD_TYPE", buildConfig.c_str());
+    mf.AddDefinition("BUILD_TYPE", buildConfig);
   }
   std::string installComponentLowerCase = cmSystemTools::LowerCase(component);
   if (installComponentLowerCase != "all") {
-    mf.AddDefinition("CMAKE_INSTALL_COMPONENT", component.c_str());
+    mf.AddDefinition("CMAKE_INSTALL_COMPONENT", component);
   }
 
   // strip on TRUE, ON, 1, one or several file names, but not on
@@ -863,9 +863,8 @@
   // forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
   // to CPack (may be used by generators like CPack RPM or DEB)
   // in order to transparently handle ABSOLUTE PATH
-  if (mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
-    mf.AddDefinition("CPACK_ABSOLUTE_DESTINATION_FILES",
-                     mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES"));
+  if (const char* def = mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
+    mf.AddDefinition("CPACK_ABSOLUTE_DESTINATION_FILES", def);
   }
 
   // Now rebuild the list of files after installation
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
index c6018cf..89c3b1c 100644
--- a/Source/CPack/cpack.cxx
+++ b/Source/CPack/cpack.cxx
@@ -270,7 +270,7 @@
     }
 
     if (!cpackBuildConfig.empty()) {
-      globalMF.AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig.c_str());
+      globalMF.AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig);
     }
 
     if (cmSystemTools::FileExists(cpackConfigFile)) {
@@ -292,24 +292,21 @@
     }
 
     if (!generator.empty()) {
-      globalMF.AddDefinition("CPACK_GENERATOR", generator.c_str());
+      globalMF.AddDefinition("CPACK_GENERATOR", generator);
     }
     if (!cpackProjectName.empty()) {
-      globalMF.AddDefinition("CPACK_PACKAGE_NAME", cpackProjectName.c_str());
+      globalMF.AddDefinition("CPACK_PACKAGE_NAME", cpackProjectName);
     }
     if (!cpackProjectVersion.empty()) {
-      globalMF.AddDefinition("CPACK_PACKAGE_VERSION",
-                             cpackProjectVersion.c_str());
+      globalMF.AddDefinition("CPACK_PACKAGE_VERSION", cpackProjectVersion);
     }
     if (!cpackProjectVendor.empty()) {
-      globalMF.AddDefinition("CPACK_PACKAGE_VENDOR",
-                             cpackProjectVendor.c_str());
+      globalMF.AddDefinition("CPACK_PACKAGE_VENDOR", cpackProjectVendor);
     }
     // if this is not empty it has been set on the command line
     // go for it. Command line override values set in config file.
     if (!cpackProjectDirectory.empty()) {
-      globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY",
-                             cpackProjectDirectory.c_str());
+      globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY", cpackProjectDirectory);
     }
     // The value has not been set on the command line
     else {
@@ -318,11 +315,11 @@
       // use default value iff no value has been provided by the config file
       if (!globalMF.IsSet("CPACK_PACKAGE_DIRECTORY")) {
         globalMF.AddDefinition("CPACK_PACKAGE_DIRECTORY",
-                               cpackProjectDirectory.c_str());
+                               cpackProjectDirectory);
       }
     }
     for (auto const& cd : definitions.Map) {
-      globalMF.AddDefinition(cd.first, cd.second.c_str());
+      globalMF.AddDefinition(cd.first, cd.second);
     }
 
     const char* cpackModulesPath = globalMF.GetDefinition("CPACK_MODULE_PATH");
@@ -426,7 +423,7 @@
               std::ostringstream ostr;
               ostr << projVersionMajor << "." << projVersionMinor << "."
                    << projVersionPatch;
-              mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str().c_str());
+              mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str());
             }
 
             int res = cpackGenerator->DoPackage();
diff --git a/Source/CTest/cmCTestBuildCommand.cxx b/Source/CTest/cmCTestBuildCommand.cxx
index 2eacaf1..e71eafe 100644
--- a/Source/CTest/cmCTestBuildCommand.cxx
+++ b/Source/CTest/cmCTestBuildCommand.cxx
@@ -156,15 +156,14 @@
   if (this->Values[ctb_NUMBER_ERRORS] && *this->Values[ctb_NUMBER_ERRORS]) {
     std::ostringstream str;
     str << this->Handler->GetTotalErrors();
-    this->Makefile->AddDefinition(this->Values[ctb_NUMBER_ERRORS],
-                                  str.str().c_str());
+    this->Makefile->AddDefinition(this->Values[ctb_NUMBER_ERRORS], str.str());
   }
   if (this->Values[ctb_NUMBER_WARNINGS] &&
       *this->Values[ctb_NUMBER_WARNINGS]) {
     std::ostringstream str;
     str << this->Handler->GetTotalWarnings();
     this->Makefile->AddDefinition(this->Values[ctb_NUMBER_WARNINGS],
-                                  str.str().c_str());
+                                  str.str());
   }
   return ret;
 }
diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx
index 2b73d40..8ceca08 100644
--- a/Source/CTest/cmCTestHandlerCommand.cxx
+++ b/Source/CTest/cmCTestHandlerCommand.cxx
@@ -112,17 +112,17 @@
       foundBadArgument = true;
     }
   }
-  bool capureCMakeError = (this->Values[ct_CAPTURE_CMAKE_ERROR] &&
-                           *this->Values[ct_CAPTURE_CMAKE_ERROR]);
+  bool captureCMakeError = (this->Values[ct_CAPTURE_CMAKE_ERROR] &&
+                            *this->Values[ct_CAPTURE_CMAKE_ERROR]);
   // now that arguments are parsed check to see if there is a
   // CAPTURE_CMAKE_ERROR specified let the errorState object know.
-  if (capureCMakeError) {
+  if (captureCMakeError) {
     errorState.CaptureCMakeError();
   }
   // if we found a bad argument then exit before running command
   if (foundBadArgument) {
     // store the cmake error
-    if (capureCMakeError) {
+    if (captureCMakeError) {
       this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
                                     "-1");
       std::string const err = this->GetName() + " " + status.GetError();
@@ -191,7 +191,7 @@
     cmCTestLog(this->CTest, ERROR_MESSAGE,
                "Cannot instantiate test handler " << this->GetName()
                                                   << std::endl);
-    if (capureCMakeError) {
+    if (captureCMakeError) {
       this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
                                     "-1");
       std::string const& err = status.GetError();
@@ -215,7 +215,7 @@
     this->SetError("failed to change directory to " +
                    this->CTest->GetCTestConfiguration("BuildDirectory") +
                    " : " + std::strerror(workdir.GetLastResult()));
-    if (capureCMakeError) {
+    if (captureCMakeError) {
       this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR],
                                     "-1");
       cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -230,12 +230,11 @@
   if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) {
     std::ostringstream str;
     str << res;
-    this->Makefile->AddDefinition(this->Values[ct_RETURN_VALUE],
-                                  str.str().c_str());
+    this->Makefile->AddDefinition(this->Values[ct_RETURN_VALUE], str.str());
   }
   this->ProcessAdditionalValues(handler);
   // log the error message if there was an error
-  if (capureCMakeError) {
+  if (captureCMakeError) {
     const char* returnString = "0";
     if (cmSystemTools::GetErrorOccuredFlag()) {
       returnString = "-1";
diff --git a/Source/CTest/cmCTestMemCheckCommand.cxx b/Source/CTest/cmCTestMemCheckCommand.cxx
index 7dad1ce..d7d42bf 100644
--- a/Source/CTest/cmCTestMemCheckCommand.cxx
+++ b/Source/CTest/cmCTestMemCheckCommand.cxx
@@ -3,7 +3,6 @@
 #include "cmCTestMemCheckCommand.h"
 
 #include <sstream>
-#include <string>
 #include <vector>
 
 #include "cmCTest.h"
@@ -47,7 +46,6 @@
   if (this->Values[ctm_DEFECT_COUNT] && *this->Values[ctm_DEFECT_COUNT]) {
     std::ostringstream str;
     str << static_cast<cmCTestMemCheckHandler*>(handler)->GetDefectCount();
-    this->Makefile->AddDefinition(this->Values[ctm_DEFECT_COUNT],
-                                  str.str().c_str());
+    this->Makefile->AddDefinition(this->Values[ctm_DEFECT_COUNT], str.str());
   }
 }
diff --git a/Source/CTest/cmCTestRunScriptCommand.cxx b/Source/CTest/cmCTestRunScriptCommand.cxx
index a7e47d3..c03cffd 100644
--- a/Source/CTest/cmCTestRunScriptCommand.cxx
+++ b/Source/CTest/cmCTestRunScriptCommand.cxx
@@ -43,7 +43,7 @@
                                       args[i].c_str(), !np, &ret);
       std::ostringstream str;
       str << ret;
-      this->Makefile->AddDefinition(returnVariable, str.str().c_str());
+      this->Makefile->AddDefinition(returnVariable, str.str());
     }
   }
   return true;
diff --git a/Source/CTest/cmCTestScriptHandler.cxx b/Source/CTest/cmCTestScriptHandler.cxx
index 85040dd..7a5b8d1 100644
--- a/Source/CTest/cmCTestScriptHandler.cxx
+++ b/Source/CTest/cmCTestScriptHandler.cxx
@@ -168,7 +168,7 @@
     auto itime = cmDurationTo<unsigned int>(std::chrono::steady_clock::now() -
                                             this->ScriptStartTime);
     auto timeString = std::to_string(itime);
-    this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString.c_str());
+    this->Makefile->AddDefinition("CTEST_ELAPSED_TIME", timeString);
   }
 }
 
@@ -352,21 +352,21 @@
   this->CreateCMake();
 
   // set a variable with the path to the current script
-  this->Makefile->AddDefinition(
-    "CTEST_SCRIPT_DIRECTORY", cmSystemTools::GetFilenamePath(script).c_str());
-  this->Makefile->AddDefinition(
-    "CTEST_SCRIPT_NAME", cmSystemTools::GetFilenameName(script).c_str());
+  this->Makefile->AddDefinition("CTEST_SCRIPT_DIRECTORY",
+                                cmSystemTools::GetFilenamePath(script));
+  this->Makefile->AddDefinition("CTEST_SCRIPT_NAME",
+                                cmSystemTools::GetFilenameName(script));
   this->Makefile->AddDefinition("CTEST_EXECUTABLE_NAME",
-                                cmSystemTools::GetCTestCommand().c_str());
+                                cmSystemTools::GetCTestCommand());
   this->Makefile->AddDefinition("CMAKE_EXECUTABLE_NAME",
-                                cmSystemTools::GetCMakeCommand().c_str());
-  this->Makefile->AddDefinition("CTEST_RUN_CURRENT_SCRIPT", true);
+                                cmSystemTools::GetCMakeCommand());
+  this->Makefile->AddDefinitionBool("CTEST_RUN_CURRENT_SCRIPT", true);
   this->SetRunCurrentScript(true);
   this->UpdateElapsedTime();
 
   // add the script arg if defined
   if (!script_arg.empty()) {
-    this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg.c_str());
+    this->Makefile->AddDefinition("CTEST_SCRIPT_ARG", script_arg);
   }
 
 #if defined(__CYGWIN__)
@@ -398,7 +398,7 @@
   const std::map<std::string, std::string>& defs =
     this->CTest->GetDefinitions();
   for (auto const& d : defs) {
-    this->Makefile->AddDefinition(d.first, d.second.c_str());
+    this->Makefile->AddDefinition(d.first, d.second);
   }
 
   // finally read in the script
diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx
index bf43d88..58c0a1b 100644
--- a/Source/CTest/cmCTestSubmitCommand.cxx
+++ b/Source/CTest/cmCTestSubmitCommand.cxx
@@ -143,7 +143,7 @@
 
   if (this->Values[cts_BUILD_ID] && *this->Values[cts_BUILD_ID]) {
     this->Makefile->AddDefinition(this->Values[cts_BUILD_ID],
-                                  this->CTest->GetBuildID().c_str());
+                                  this->CTest->GetBuildID());
   }
 
   return ret;
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index cfbdad0..5134407 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -1714,8 +1714,7 @@
   cm.GetCurrentSnapshot().SetDefaultDefinitions();
   cmGlobalGenerator gg(&cm);
   cmMakefile mf(&gg, cm.GetCurrentSnapshot());
-  mf.AddDefinition("CTEST_CONFIGURATION_TYPE",
-                   this->CTest->GetConfigType().c_str());
+  mf.AddDefinition("CTEST_CONFIGURATION_TYPE", this->CTest->GetConfigType());
 
   // Add handler for ADD_TEST
   auto newCom1 = cm::make_unique<cmCTestAddTestCommand>();
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
index b4b480b..cf71052 100644
--- a/Source/cmAlgorithms.h
+++ b/Source/cmAlgorithms.h
@@ -19,44 +19,6 @@
 #include <utility>
 #include <vector>
 
-inline bool cmHasLiteralPrefixImpl(const std::string& str1, const char* str2,
-                                   size_t N)
-{
-  return strncmp(str1.c_str(), str2, N) == 0;
-}
-
-inline bool cmHasLiteralPrefixImpl(const char* str1, const char* str2,
-                                   size_t N)
-{
-  return strncmp(str1, str2, N) == 0;
-}
-
-inline bool cmHasLiteralSuffixImpl(const std::string& str1, const char* str2,
-                                   size_t N)
-{
-  size_t len = str1.size();
-  return len >= N && strcmp(str1.c_str() + len - N, str2) == 0;
-}
-
-inline bool cmHasLiteralSuffixImpl(const char* str1, const char* str2,
-                                   size_t N)
-{
-  size_t len = strlen(str1);
-  return len >= N && strcmp(str1 + len - N, str2) == 0;
-}
-
-template <typename T, size_t N>
-bool cmHasLiteralPrefix(const T& str1, const char (&str2)[N])
-{
-  return cmHasLiteralPrefixImpl(str1, str2, N - 1);
-}
-
-template <typename T, size_t N>
-bool cmHasLiteralSuffix(const T& str1, const char (&str2)[N])
-{
-  return cmHasLiteralSuffixImpl(str1, str2, N - 1);
-}
-
 struct cmStrCmp
 {
   cmStrCmp(const char* test)
@@ -327,6 +289,13 @@
   return str.compare(0, prefix.size(), prefix) == 0;
 }
 
+/** Returns true if string @a str starts with string @a prefix.  **/
+template <size_t N>
+inline bool cmHasLiteralPrefix(cm::string_view str, const char (&prefix)[N])
+{
+  return cmHasPrefix(str, cm::string_view(prefix, N - 1));
+}
+
 /** Returns true if string @a str ends with the character @a suffix.  **/
 inline bool cmHasSuffix(cm::string_view str, char suffix)
 {
@@ -340,6 +309,13 @@
     str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
 }
 
+/** Returns true if string @a str ends with string @a suffix.  **/
+template <size_t N>
+inline bool cmHasLiteralSuffix(cm::string_view str, const char (&suffix)[N])
+{
+  return cmHasSuffix(str, cm::string_view(suffix, N - 1));
+}
+
 /** Removes an existing suffix character of from the string @a str.  **/
 inline void cmStripSuffixIfExists(std::string& str, char suffix)
 {
diff --git a/Source/cmAuxSourceDirectoryCommand.cxx b/Source/cmAuxSourceDirectoryCommand.cxx
index 106e7a7..c1a6e7f 100644
--- a/Source/cmAuxSourceDirectoryCommand.cxx
+++ b/Source/cmAuxSourceDirectoryCommand.cxx
@@ -74,6 +74,6 @@
     sourceListValue += ";";
   }
   sourceListValue += cmJoin(files, ";");
-  this->Makefile->AddDefinition(args[1], sourceListValue.c_str());
+  this->Makefile->AddDefinition(args[1], sourceListValue);
   return true;
 }
diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx
index 428a0b2..e9e1d49 100644
--- a/Source/cmBuildCommand.cxx
+++ b/Source/cmBuildCommand.cxx
@@ -92,7 +92,7 @@
     this->Makefile->GetGlobalGenerator()->GenerateCMakeBuildCommand(
       target, configuration, "", this->Makefile->IgnoreErrorsCMP0061());
 
-  this->Makefile->AddDefinition(variable, makecommand.c_str());
+  this->Makefile->AddDefinition(variable, makecommand);
 
   return true;
 }
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
index 54f08bb..b4cd2a5 100644
--- a/Source/cmCMakeHostSystemInformationCommand.cxx
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -55,7 +55,7 @@
     result_list += value;
   }
 
-  this->Makefile->AddDefinition(variable, result_list.c_str());
+  this->Makefile->AddDefinition(variable, result_list);
 
   return true;
 }
diff --git a/Source/cmCMakeMinimumRequired.cxx b/Source/cmCMakeMinimumRequired.cxx
index 4b4bca2..f2eae38 100644
--- a/Source/cmCMakeMinimumRequired.cxx
+++ b/Source/cmCMakeMinimumRequired.cxx
@@ -61,8 +61,7 @@
   }
 
   // Save the required version string.
-  this->Makefile->AddDefinition("CMAKE_MINIMUM_REQUIRED_VERSION",
-                                version_min.c_str());
+  this->Makefile->AddDefinition("CMAKE_MINIMUM_REQUIRED_VERSION", version_min);
 
   // Get the current version number.
   unsigned int current_major = cmVersion::GetMajorVersion();
diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx
index 8da5ef7..ce046fc 100644
--- a/Source/cmCMakePolicyCommand.cxx
+++ b/Source/cmCMakePolicyCommand.cxx
@@ -209,8 +209,7 @@
   }
 
   // Lookup the policy warning.
-  this->Makefile->AddDefinition(var,
-                                cmPolicies::GetPolicyWarning(pid).c_str());
+  this->Makefile->AddDefinition(var, cmPolicies::GetPolicyWarning(pid));
 
   return true;
 }
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index 8c2d987..80ca898 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -65,8 +65,10 @@
 
 void CCONV cmAddDefinition(void* arg, const char* name, const char* value)
 {
-  cmMakefile* mf = static_cast<cmMakefile*>(arg);
-  mf->AddDefinition(name, value);
+  if (value) {
+    cmMakefile* mf = static_cast<cmMakefile*>(arg);
+    mf->AddDefinition(name, value);
+  }
 }
 
 /* Add a definition to this makefile and the global cmake cache. */
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index f12ef0b..d780af6 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -932,7 +932,7 @@
                                      cmStateEnums::INTERNAL);
 
   if (!outputVariable.empty()) {
-    this->Makefile->AddDefinition(outputVariable, output.c_str());
+    this->Makefile->AddDefinition(outputVariable, output);
   }
 
   if (this->SrcFileSignature) {
@@ -961,8 +961,7 @@
     }
 
     if (!copyFileError.empty()) {
-      this->Makefile->AddDefinition(copyFileError,
-                                    copyFileErrorMessage.c_str());
+      this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage);
     }
   }
   return res;
diff --git a/Source/cmCreateTestSourceList.cxx b/Source/cmCreateTestSourceList.cxx
index b78493f..427db72 100644
--- a/Source/cmCreateTestSourceList.cxx
+++ b/Source/cmCreateTestSourceList.cxx
@@ -125,16 +125,15 @@
   }
   if (!extraInclude.empty()) {
     this->Makefile->AddDefinition("CMAKE_TESTDRIVER_EXTRA_INCLUDES",
-                                  extraInclude.c_str());
+                                  extraInclude);
   }
   if (!function.empty()) {
-    this->Makefile->AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION",
-                                  function.c_str());
+    this->Makefile->AddDefinition("CMAKE_TESTDRIVER_ARGVC_FUNCTION", function);
   }
   this->Makefile->AddDefinition("CMAKE_FORWARD_DECLARE_TESTS",
-                                forwardDeclareCode.c_str());
+                                forwardDeclareCode);
   this->Makefile->AddDefinition("CMAKE_FUNCTION_TABLE_ENTIRES",
-                                functionMapCode.c_str());
+                                functionMapCode);
   bool res = true;
   if (!this->Makefile->ConfigureFile(configFile, driver, false, true, false)) {
     res = false;
@@ -154,6 +153,6 @@
     sourceListValue += *i;
   }
 
-  this->Makefile->AddDefinition(sourceList, sourceListValue.c_str());
+  this->Makefile->AddDefinition(sourceList, sourceListValue);
   return res;
 }
diff --git a/Source/cmDefinitions.cxx b/Source/cmDefinitions.cxx
index 894447c..42e70d6 100644
--- a/Source/cmDefinitions.cxx
+++ b/Source/cmDefinitions.cxx
@@ -13,10 +13,12 @@
                                                      StackIter end, bool raise)
 {
   assert(begin != end);
-  MapType::iterator i = begin->Map.find(key);
-  if (i != begin->Map.end()) {
-    i->second.Used = true;
-    return i->second;
+  {
+    MapType::iterator it = begin->Map.find(key);
+    if (it != begin->Map.end()) {
+      it->second.Used = true;
+      return it->second;
+    }
   }
   StackIter it = begin;
   ++it;
@@ -27,14 +29,14 @@
   if (!raise) {
     return def;
   }
-  return begin->Map.insert(MapType::value_type(key, def)).first->second;
+  return begin->Map.emplace(key, def).first->second;
 }
 
 const std::string* cmDefinitions::Get(const std::string& key, StackIter begin,
                                       StackIter end)
 {
   Def const& def = cmDefinitions::GetInternal(key, begin, end, false);
-  return def.Exists ? &def : nullptr;
+  return def.Exists ? &def.Value : nullptr;
 }
 
 void cmDefinitions::Raise(const std::string& key, StackIter begin,
@@ -47,19 +49,23 @@
                            StackIter end)
 {
   for (StackIter it = begin; it != end; ++it) {
-    MapType::const_iterator i = it->Map.find(key);
-    if (i != it->Map.end()) {
+    if (it->Map.find(key) != it->Map.end()) {
       return true;
     }
   }
   return false;
 }
 
-void cmDefinitions::Set(const std::string& key, const char* value)
+void cmDefinitions::Set(const std::string& key, cm::string_view value)
 {
   this->Map[key] = Def(value);
 }
 
+void cmDefinitions::Unset(const std::string& key)
+{
+  this->Map[key] = Def();
+}
+
 std::vector<std::string> cmDefinitions::UnusedKeys() const
 {
   std::vector<std::string> keys;
@@ -97,8 +103,8 @@
 std::vector<std::string> cmDefinitions::ClosureKeys(StackIter begin,
                                                     StackIter end)
 {
-  std::set<std::string> bound;
   std::vector<std::string> defined;
+  std::set<std::string> bound;
 
   for (StackIter it = begin; it != end; ++it) {
     defined.reserve(defined.size() + it->Map.size());
diff --git a/Source/cmDefinitions.h b/Source/cmDefinitions.h
index 6c252be..4d8810a 100644
--- a/Source/cmDefinitions.h
+++ b/Source/cmDefinitions.h
@@ -5,12 +5,14 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include "cm_string_view.hxx"
+
+#include "cmLinkedTree.h"
+
 #include <string>
 #include <unordered_map>
 #include <vector>
 
-#include "cmLinkedTree.h"
-
 /** \class cmDefinitions
  * \brief Store a scope of variable definitions for CMake language.
  *
@@ -30,8 +32,11 @@
 
   static bool HasKey(const std::string& key, StackIter begin, StackIter end);
 
-  /** Set (or unset if null) a value associated with a key.  */
-  void Set(const std::string& key, const char* value);
+  /** Set a value associated with a key.  */
+  void Set(const std::string& key, cm::string_view value);
+
+  /** Unset a definition.  */
+  void Unset(const std::string& key);
 
   std::vector<std::string> UnusedKeys() const;
 
@@ -40,24 +45,17 @@
   static cmDefinitions MakeClosure(StackIter begin, StackIter end);
 
 private:
-  // String with existence boolean.
-  struct Def : public std::string
+  /** String with existence boolean.  */
+  struct Def
   {
-  private:
-    typedef std::string std_string;
-
   public:
     Def() = default;
-    Def(const char* v)
-      : std_string(v ? v : "")
-      , Exists(v ? true : false)
-    {
-    }
-    Def(const std_string& v)
-      : std_string(v)
+    Def(cm::string_view value)
+      : Value(value)
       , Exists(true)
     {
     }
+    std::string Value;
     bool Exists = false;
     bool Used = false;
   };
diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx
index 4b559e7..bc1d173 100644
--- a/Source/cmExecProgramCommand.cxx
+++ b/Source/cmExecProgramCommand.cxx
@@ -103,7 +103,7 @@
     }
 
     std::string coutput = std::string(output, first, last - first + 1);
-    this->Makefile->AddDefinition(output_variable, coutput.c_str());
+    this->Makefile->AddDefinition(output_variable, coutput);
   }
 
   if (!return_variable.empty()) {
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index 689fc20..8d91f43 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -332,7 +332,7 @@
           }
         }
         this->Makefile->AddDefinition(arguments.ResultsVariable,
-                                      cmJoin(res, ";").c_str());
+                                      cmJoin(res, ";"));
       } break;
       case cmsysProcess_State_Exception:
         this->Makefile->AddDefinition(arguments.ResultsVariable,
diff --git a/Source/cmFLTKWrapUICommand.cxx b/Source/cmFLTKWrapUICommand.cxx
index 70800b4..b7a2b27 100644
--- a/Source/cmFLTKWrapUICommand.cxx
+++ b/Source/cmFLTKWrapUICommand.cxx
@@ -117,8 +117,9 @@
     }
     sourceListValue += generatedSourcesClasses[classNum]->GetFullPath();
   }
+
   std::string const varName = target + "_FLTK_UI_SRCS";
-  this->Makefile->AddDefinition(varName, sourceListValue.c_str());
+  this->Makefile->AddDefinition(varName, sourceListValue);
 
   this->Makefile->AddFinalAction(
     [target](cmMakefile& makefile) { FinalAction(makefile, target); });
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 9871f49..a8ee6a8 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -365,7 +365,7 @@
       }
     }
   }
-  this->Makefile->AddDefinition(variable, output.c_str());
+  this->Makefile->AddDefinition(variable, output);
   return true;
 }
 
@@ -383,7 +383,7 @@
   if (hash) {
     std::string out = hash->HashFile(args[1]);
     if (!out.empty()) {
-      this->Makefile->AddDefinition(args[2], out.c_str());
+      this->Makefile->AddDefinition(args[2], out);
       return true;
     }
     std::ostringstream e;
@@ -751,7 +751,7 @@
   }
 
   // Save the output in a makefile variable.
-  this->Makefile->AddDefinition(outVar, output.c_str());
+  this->Makefile->AddDefinition(outVar, output);
   return true;
 }
 
@@ -938,7 +938,7 @@
 
   std::sort(files.begin(), files.end());
   files.erase(std::unique(files.begin(), files.end()), files.end());
-  this->Makefile->AddDefinition(variable, cmJoin(files, ";").c_str());
+  this->Makefile->AddDefinition(variable, cmJoin(files, ";"));
   return true;
 }
 
@@ -1071,6 +1071,7 @@
   std::string file;
   const char* oldRPath = nullptr;
   const char* newRPath = nullptr;
+  bool removeEnvironmentRPath = false;
   enum Doing
   {
     DoingNone,
@@ -1086,6 +1087,8 @@
       doing = DoingNew;
     } else if (args[i] == "FILE") {
       doing = DoingFile;
+    } else if (args[i] == "INSTALL_REMOVE_ENVIRONMENT_RPATH") {
+      removeEnvironmentRPath = true;
     } else if (doing == DoingFile) {
       file = args[i];
       doing = DoingNone;
@@ -1124,7 +1127,9 @@
   cmFileTimes const ft(file);
   std::string emsg;
   bool changed;
-  if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg, &changed)) {
+
+  if (!cmSystemTools::ChangeRPath(file, oldRPath, newRPath,
+                                  removeEnvironmentRPath, &emsg, &changed)) {
     std::ostringstream e;
     /* clang-format off */
     e << "RPATH_CHANGE could not write new RPATH:\n"
@@ -1298,14 +1303,14 @@
     if (cmELF::StringEntry const* se_rpath = elf.GetRPath()) {
       std::string rpath(se_rpath->Value);
       std::replace(rpath.begin(), rpath.end(), ':', ';');
-      this->Makefile->AddDefinition(arguments.RPath, rpath.c_str());
+      this->Makefile->AddDefinition(arguments.RPath, rpath);
     }
   }
   if (!arguments.RunPath.empty()) {
     if (cmELF::StringEntry const* se_runpath = elf.GetRunPath()) {
       std::string runpath(se_runpath->Value);
       std::replace(runpath.begin(), runpath.end(), ':', ';');
-      this->Makefile->AddDefinition(arguments.RunPath, runpath.c_str());
+      this->Makefile->AddDefinition(arguments.RunPath, runpath);
     }
   }
 
@@ -1316,7 +1321,7 @@
     this->SetError(error);
     return false;
   }
-  this->Makefile->AddDefinition(arguments.Error, error.c_str());
+  this->Makefile->AddDefinition(arguments.Error, error);
   return true;
 #endif
 }
@@ -1354,7 +1359,7 @@
   }
 
   std::string res = cmSystemTools::RelativePath(directoryName, fileName);
-  this->Makefile->AddDefinition(outVar, res.c_str());
+  this->Makefile->AddDefinition(outVar, res);
   return true;
 }
 
@@ -1460,7 +1465,7 @@
 
   std::string value = cmJoin(
     cmMakeRange(path).transform(nativePath ? ToNativePath : ToCMakePath), ";");
-  this->Makefile->AddDefinition(args[2], value.c_str());
+  this->Makefile->AddDefinition(args[2], value);
   return true;
 }
 
@@ -1800,7 +1805,7 @@
       if (!statusVar.empty()) {
         std::ostringstream result;
         result << 0 << ";\"" << msg;
-        this->Makefile->AddDefinition(statusVar, result.str().c_str());
+        this->Makefile->AddDefinition(statusVar, result.str());
       }
       return true;
     }
@@ -1949,7 +1954,7 @@
     std::ostringstream result;
     result << static_cast<int>(res) << ";\"" << ::curl_easy_strerror(res)
            << "\"";
-    this->Makefile->AddDefinition(statusVar, result.str().c_str());
+    this->Makefile->AddDefinition(statusVar, result.str());
   }
 
   ::curl_global_cleanup();
@@ -1981,7 +1986,7 @@
         std::string status = "1;HASH mismatch: "
                              "expected: " +
           expectedHash + " actual: " + actualHash;
-        this->Makefile->AddDefinition(statusVar, status.c_str());
+        this->Makefile->AddDefinition(statusVar, status);
       }
 
       this->SetError(oss.str());
@@ -2236,7 +2241,7 @@
     std::ostringstream result;
     result << static_cast<int>(res) << ";\"" << ::curl_easy_strerror(res)
            << "\"";
-    this->Makefile->AddDefinition(statusVar, result.str().c_str());
+    this->Makefile->AddDefinition(statusVar, result.str());
   }
 
   ::curl_global_cleanup();
@@ -2261,7 +2266,7 @@
       log += "\n";
     }
 
-    this->Makefile->AddDefinition(logVar, log.c_str());
+    this->Makefile->AddDefinition(logVar, log);
   }
 
   return true;
@@ -2479,7 +2484,7 @@
   }
 
   if (!resultVariable.empty()) {
-    this->Makefile->AddDefinition(resultVariable, result.c_str());
+    this->Makefile->AddDefinition(resultVariable, result);
   }
 
   return true;
@@ -2528,7 +2533,7 @@
   cmTimestamp timestamp;
   std::string result =
     timestamp.FileModificationTime(filename.c_str(), formatString, utcFlag);
-  this->Makefile->AddDefinition(outputVariable, result.c_str());
+  this->Makefile->AddDefinition(outputVariable, result);
 
   return true;
 }
@@ -2556,8 +2561,7 @@
   }
 
   this->Makefile->AddDefinition(
-    outputVariable,
-    std::to_string(cmSystemTools::FileLength(filename)).c_str());
+    outputVariable, std::to_string(cmSystemTools::FileLength(filename)));
 
   return true;
 }
@@ -2584,7 +2588,7 @@
     return false;
   }
 
-  this->Makefile->AddDefinition(outputVariable, result.c_str());
+  this->Makefile->AddDefinition(outputVariable, result);
 
   return true;
 }
@@ -2630,7 +2634,7 @@
   if (fileName == newFileName) {
     result = "CREATE_LINK cannot use same file and newfile";
     if (!arguments.Result.empty()) {
-      this->Makefile->AddDefinition(arguments.Result, result.c_str());
+      this->Makefile->AddDefinition(arguments.Result, result);
       return true;
     }
     this->SetError(result);
@@ -2641,7 +2645,7 @@
   if (!arguments.Symbolic && !cmSystemTools::FileExists(fileName)) {
     result = "Cannot hard link \'" + fileName + "\' as it does not exist.";
     if (!arguments.Result.empty()) {
-      this->Makefile->AddDefinition(arguments.Result, result.c_str());
+      this->Makefile->AddDefinition(arguments.Result, result);
       return true;
     }
     this->SetError(result);
@@ -2658,7 +2662,7 @@
       << cmSystemTools::GetLastSystemError() << "\n";
 
     if (!arguments.Result.empty()) {
-      this->Makefile->AddDefinition(arguments.Result, e.str().c_str());
+      this->Makefile->AddDefinition(arguments.Result, e.str());
       return true;
     }
     this->SetError(e.str());
@@ -2693,7 +2697,7 @@
   }
 
   if (!arguments.Result.empty()) {
-    this->Makefile->AddDefinition(arguments.Result, result.c_str());
+    this->Makefile->AddDefinition(arguments.Result, result);
   }
 
   return true;
@@ -2821,7 +2825,7 @@
       std::string varName =
         parsedArgs.ConflictingDependenciesPrefix + "_" + val.first;
       std::string pathsStr = cmJoin(paths, ";");
-      this->Makefile->AddDefinition(varName, pathsStr.c_str());
+      this->Makefile->AddDefinition(varName, pathsStr);
     } else {
       std::ostringstream e;
       e << "Multiple conflicting paths found for " << val.first << ":";
@@ -2851,18 +2855,16 @@
 
   if (!parsedArgs.ResolvedDependenciesVar.empty()) {
     std::string val = cmJoin(deps, ";");
-    this->Makefile->AddDefinition(parsedArgs.ResolvedDependenciesVar,
-                                  val.c_str());
+    this->Makefile->AddDefinition(parsedArgs.ResolvedDependenciesVar, val);
   }
   if (!parsedArgs.UnresolvedDependenciesVar.empty()) {
     std::string val = cmJoin(unresolvedDeps, ";");
-    this->Makefile->AddDefinition(parsedArgs.UnresolvedDependenciesVar,
-                                  val.c_str());
+    this->Makefile->AddDefinition(parsedArgs.UnresolvedDependenciesVar, val);
   }
   if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
     std::string val = cmJoin(conflictingDeps, ";");
     this->Makefile->AddDefinition(
-      parsedArgs.ConflictingDependenciesPrefix + "_FILENAMES", val.c_str());
+      parsedArgs.ConflictingDependenciesPrefix + "_FILENAMES", val);
   }
   return true;
 }
diff --git a/Source/cmFileInstaller.cxx b/Source/cmFileInstaller.cxx
index d4f76fd..9378439 100644
--- a/Source/cmFileInstaller.cxx
+++ b/Source/cmFileInstaller.cxx
@@ -38,7 +38,7 @@
 {
   // Save the updated install manifest.
   this->Makefile->AddDefinition("CMAKE_INSTALL_MANIFEST_FILES",
-                                this->Manifest.c_str());
+                                this->Manifest);
 }
 
 void cmFileInstaller::ManifestAppend(std::string const& file)
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index e4551dd..db3f4ef 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -678,7 +678,9 @@
   } else {
     this->OriginalDefs[var].exists = false;
   }
-  this->Makefile->AddDefinition(var, val);
+  if (val) {
+    this->Makefile->AddDefinition(var, val);
+  }
 }
 
 void cmFindPackageCommand::RestoreFindDefinitions()
@@ -686,7 +688,7 @@
   for (auto const& i : this->OriginalDefs) {
     OriginalDef const& od = i.second;
     if (od.exists) {
-      this->Makefile->AddDefinition(i.first, od.value.c_str());
+      this->Makefile->AddDefinition(i.first, od.value);
     } else {
       this->Makefile->RemoveDefinition(i.first);
     }
@@ -960,7 +962,7 @@
   std::string fileVar = this->Name;
   fileVar += "_CONFIG";
   if (found) {
-    this->Makefile->AddDefinition(fileVar, this->FileFound.c_str());
+    this->Makefile->AddDefinition(fileVar, this->FileFound);
   } else {
     this->Makefile->RemoveDefinition(fileVar);
   }
@@ -982,11 +984,9 @@
     sep = ";";
   }
 
-  this->Makefile->AddDefinition(consideredConfigsVar,
-                                consideredConfigFiles.c_str());
+  this->Makefile->AddDefinition(consideredConfigsVar, consideredConfigFiles);
 
-  this->Makefile->AddDefinition(consideredVersionsVar,
-                                consideredVersions.c_str());
+  this->Makefile->AddDefinition(consideredVersionsVar, consideredVersions);
 
   return result;
 }
@@ -1615,8 +1615,8 @@
   this->Makefile->RemoveDefinition("PACKAGE_VERSION_EXACT");
 
   // Set the input variables.
-  this->Makefile->AddDefinition("PACKAGE_FIND_NAME", this->Name.c_str());
-  this->Makefile->AddDefinition("PACKAGE_FIND_VERSION", this->Version.c_str());
+  this->Makefile->AddDefinition("PACKAGE_FIND_NAME", this->Name);
+  this->Makefile->AddDefinition("PACKAGE_FIND_VERSION", this->Version);
   char buf[64];
   sprintf(buf, "%u", this->VersionMajor);
   this->Makefile->AddDefinition("PACKAGE_FIND_VERSION_MAJOR", buf);
@@ -1693,7 +1693,7 @@
   if (this->VersionFound.empty()) {
     this->Makefile->RemoveDefinition(ver);
   } else {
-    this->Makefile->AddDefinition(ver, this->VersionFound.c_str());
+    this->Makefile->AddDefinition(ver, this->VersionFound);
   }
 
   // Store the version components.
diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx
index e3918b5..06dce2c 100644
--- a/Source/cmForEachCommand.cxx
+++ b/Source/cmForEachCommand.cxx
@@ -53,7 +53,7 @@
 
       for (std::string const& arg : cmMakeRange(this->Args).advance(1)) {
         // set the variable to the loop value
-        mf.AddDefinition(this->Args[0], arg.c_str());
+        mf.AddDefinition(this->Args[0], arg);
         // Invoke all the functions that were collected in the block.
         cmExecutionStatus status(mf);
         for (cmListFileFunction const& func : this->Functions) {
@@ -62,12 +62,12 @@
           if (status.GetReturnInvoked()) {
             inStatus.SetReturnInvoked();
             // restore the variable to its prior value
-            mf.AddDefinition(this->Args[0], oldDef.c_str());
+            mf.AddDefinition(this->Args[0], oldDef);
             return true;
           }
           if (status.GetBreakInvoked()) {
             // restore the variable to its prior value
-            mf.AddDefinition(this->Args[0], oldDef.c_str());
+            mf.AddDefinition(this->Args[0], oldDef);
             return true;
           }
           if (status.GetContinueInvoked()) {
@@ -80,7 +80,7 @@
       }
 
       // restore the variable to its prior value
-      mf.AddDefinition(this->Args[0], oldDef.c_str());
+      mf.AddDefinition(this->Args[0], oldDef);
       return true;
     }
     // close out a nested foreach
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index 8b664ad..6afd31a 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -55,20 +55,20 @@
   // set the value of argc
   std::ostringstream strStream;
   strStream << expandedArgs.size();
-  makefile.AddDefinition("ARGC", strStream.str().c_str());
+  makefile.AddDefinition("ARGC", strStream.str());
   makefile.MarkVariableAsUsed("ARGC");
 
   // set the values for ARGV0 ARGV1 ...
   for (unsigned int t = 0; t < expandedArgs.size(); ++t) {
     std::ostringstream tmpStream;
     tmpStream << "ARGV" << t;
-    makefile.AddDefinition(tmpStream.str(), expandedArgs[t].c_str());
+    makefile.AddDefinition(tmpStream.str(), expandedArgs[t]);
     makefile.MarkVariableAsUsed(tmpStream.str());
   }
 
   // define the formal arguments
   for (unsigned int j = 1; j < this->Args.size(); ++j) {
-    makefile.AddDefinition(this->Args[j], expandedArgs[j - 1].c_str());
+    makefile.AddDefinition(this->Args[j], expandedArgs[j - 1]);
   }
 
   // define ARGV and ARGN
@@ -76,9 +76,9 @@
   std::vector<std::string>::const_iterator eit =
     expandedArgs.begin() + (this->Args.size() - 1);
   std::string argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
-  makefile.AddDefinition("ARGV", argvDef.c_str());
+  makefile.AddDefinition("ARGV", argvDef);
   makefile.MarkVariableAsUsed("ARGV");
-  makefile.AddDefinition("ARGN", argnDef.c_str());
+  makefile.AddDefinition("ARGN", argnDef);
   makefile.MarkVariableAsUsed("ARGN");
 
   // Invoke all the functions that were collected in the block.
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index d828dac..49d0c47 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -1038,45 +1038,38 @@
   }
 } languageAndIdNode;
 
-#define TRANSITIVE_PROPERTY_NAME(PROPERTY) , "INTERFACE_" #PROPERTY
-
-static const char* targetPropertyTransitiveWhitelist[] = {
-  nullptr CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_NAME)
-};
-
-#undef TRANSITIVE_PROPERTY_NAME
-
-template <typename T>
 std::string getLinkedTargetsContent(
-  std::vector<T> const& libraries, cmGeneratorTarget const* target,
-  cmGeneratorTarget const* headTarget, cmGeneratorExpressionContext* context,
-  cmGeneratorExpressionDAGChecker* dagChecker,
-  const std::string& interfacePropertyName)
+  cmGeneratorTarget const* target, std::string const& prop,
+  cmGeneratorExpressionContext* context,
+  cmGeneratorExpressionDAGChecker* dagChecker)
 {
-  std::string linkedTargetsContent;
-  std::string sep;
-  std::string depString;
-  for (T const& l : libraries) {
-    // Broken code can have a target in its own link interface.
-    // Don't follow such link interface entries so as not to create a
-    // self-referencing loop.
-    if (l.Target && l.Target != target) {
-      std::string uniqueName =
-        target->GetGlobalGenerator()->IndexGeneratorTargetUniquely(l.Target);
-      depString += sep + "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," +
-        interfacePropertyName + ">";
-      sep = ";";
+  std::string result;
+  if (cmLinkImplementationLibraries const* impl =
+        target->GetLinkImplementationLibraries(context->Config)) {
+    for (cmLinkImplItem const& lib : impl->Libraries) {
+      if (lib.Target) {
+        // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
+        // caller's property and hand-evaluate it as if it were compiled.
+        // Create a context as cmCompiledGeneratorExpression::Evaluate does.
+        cmGeneratorExpressionContext libContext(
+          target->GetLocalGenerator(), context->Config, context->Quiet, target,
+          target, context->EvaluateForBuildsystem, lib.Backtrace,
+          context->Language);
+        std::string libResult =
+          lib.Target->EvaluateInterfaceProperty(prop, &libContext, dagChecker);
+        if (!libResult.empty()) {
+          if (result.empty()) {
+            result = std::move(libResult);
+          } else {
+            result.reserve(result.size() + 1 + libResult.size());
+            result += ";";
+            result += libResult;
+          }
+        }
+      }
     }
   }
-  if (!depString.empty()) {
-    linkedTargetsContent =
-      cmGeneratorExpressionNode::EvaluateDependentExpression(
-        depString, target->GetLocalGenerator(), context, headTarget, target,
-        dagChecker);
-  }
-  linkedTargetsContent =
-    cmGeneratorExpression::StripEmptyListElements(linkedTargetsContent);
-  return linkedTargetsContent;
+  return result;
 }
 
 static const struct TargetPropertyNode : public cmGeneratorExpressionNode
@@ -1205,67 +1198,6 @@
       return target->GetLinkerLanguage(context->Config);
     }
 
-    cmGeneratorExpressionDAGChecker dagChecker(
-      context->Backtrace, target, propertyName, content, dagCheckerParent);
-
-    switch (dagChecker.Check()) {
-      case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
-        dagChecker.ReportError(context, content->GetOriginalExpression());
-        return std::string();
-      case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
-        // No error. We just skip cyclic references.
-        return std::string();
-      case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
-        for (size_t i = 1; i < cm::size(targetPropertyTransitiveWhitelist);
-             ++i) {
-          if (targetPropertyTransitiveWhitelist[i] == propertyName) {
-            // No error. We're not going to find anything new here.
-            return std::string();
-          }
-        }
-      case cmGeneratorExpressionDAGChecker::DAG:
-        break;
-    }
-
-    std::string prop;
-    bool haveProp = false;
-    if (const char* p = target->GetProperty(propertyName)) {
-      prop = p;
-      haveProp = true;
-    }
-
-    if (dagCheckerParent) {
-      if (dagCheckerParent->EvaluatingGenexExpression() ||
-          dagCheckerParent->EvaluatingPICExpression()) {
-        // No check required.
-      } else if (dagCheckerParent->EvaluatingLinkLibraries()) {
-#define TRANSITIVE_PROPERTY_COMPARE(PROPERTY)                                 \
-  (#PROPERTY == propertyName || "INTERFACE_" #PROPERTY == propertyName) ||
-        if (CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(
-              TRANSITIVE_PROPERTY_COMPARE) false) { // NOLINT(*)
-          reportError(
-            context, content->GetOriginalExpression(),
-            "$<TARGET_PROPERTY:...> expression in link libraries "
-            "evaluation depends on target property which is transitive "
-            "over the link libraries, creating a recursion.");
-          return std::string();
-        }
-#undef TRANSITIVE_PROPERTY_COMPARE
-
-        if (!haveProp) {
-          return std::string();
-        }
-      } else {
-#define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() ||
-
-        assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
-          ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy)
-#undef ASSERT_TRANSITIVE_PROPERTY_METHOD
-      }
-    }
-
-    std::string linkedTargetsContent;
-
     std::string interfacePropertyName;
     bool isInterfaceProperty = false;
 
@@ -1287,32 +1219,64 @@
       }
     }
 #undef POPULATE_INTERFACE_PROPERTY_NAME
-    cmGeneratorTarget const* headTarget =
-      context->HeadTarget && isInterfaceProperty ? context->HeadTarget
-                                                 : target;
 
-    if (isInterfaceProperty) {
-      if (cmLinkInterfaceLibraries const* iface =
-            target->GetLinkInterfaceLibraries(context->Config, headTarget,
-                                              true)) {
-        linkedTargetsContent =
-          getLinkedTargetsContent(iface->Libraries, target, headTarget,
-                                  context, &dagChecker, interfacePropertyName);
-      }
-    } else if (!interfacePropertyName.empty()) {
-      if (cmLinkImplementationLibraries const* impl =
-            target->GetLinkImplementationLibraries(context->Config)) {
-        linkedTargetsContent =
-          getLinkedTargetsContent(impl->Libraries, target, target, context,
-                                  &dagChecker, interfacePropertyName);
+    bool evaluatingLinkLibraries = false;
+
+    if (dagCheckerParent) {
+      if (dagCheckerParent->EvaluatingGenexExpression() ||
+          dagCheckerParent->EvaluatingPICExpression()) {
+        // No check required.
+      } else if (dagCheckerParent->EvaluatingLinkLibraries()) {
+        evaluatingLinkLibraries = true;
+        if (!interfacePropertyName.empty()) {
+          reportError(
+            context, content->GetOriginalExpression(),
+            "$<TARGET_PROPERTY:...> expression in link libraries "
+            "evaluation depends on target property which is transitive "
+            "over the link libraries, creating a recursion.");
+          return std::string();
+        }
+      } else {
+#define ASSERT_TRANSITIVE_PROPERTY_METHOD(METHOD) dagCheckerParent->METHOD() ||
+        assert(CM_FOR_EACH_TRANSITIVE_PROPERTY_METHOD(
+          ASSERT_TRANSITIVE_PROPERTY_METHOD) false); // NOLINT(clang-tidy)
+#undef ASSERT_TRANSITIVE_PROPERTY_METHOD
       }
     }
 
-    if (!haveProp) {
-      if (target->IsImported() ||
-          target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
-        return linkedTargetsContent;
-      }
+    if (isInterfaceProperty) {
+      return target->EvaluateInterfaceProperty(propertyName, context,
+                                               dagCheckerParent);
+    }
+
+    cmGeneratorExpressionDAGChecker dagChecker(
+      context->Backtrace, target, propertyName, content, dagCheckerParent);
+
+    switch (dagChecker.Check()) {
+      case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+        dagChecker.ReportError(context, content->GetOriginalExpression());
+        return std::string();
+      case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+        // No error. We just skip cyclic references.
+        return std::string();
+      case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+        // We handle transitive properties above.  For non-transitive
+        // properties we accept repeats anyway.
+      case cmGeneratorExpressionDAGChecker::DAG:
+        break;
+    }
+
+    std::string result;
+    bool haveProp = false;
+    if (const char* p = target->GetProperty(propertyName)) {
+      result = p;
+      haveProp = true;
+    } else if (evaluatingLinkLibraries) {
+      return std::string();
+    }
+
+    if (!haveProp && !target->IsImported() &&
+        target->GetType() != cmStateEnums::INTERFACE_LIBRARY) {
       if (target->IsLinkInterfaceDependentBoolProperty(propertyName,
                                                        context->Config)) {
         context->HadContextSensitiveCondition = true;
@@ -1345,8 +1309,6 @@
                                                              context->Config);
         return propContent ? propContent : "";
       }
-
-      return linkedTargetsContent;
     }
 
     if (!target->IsImported() && dagCheckerParent &&
@@ -1368,15 +1330,17 @@
         return propContent ? propContent : "";
       }
     }
+
     if (!interfacePropertyName.empty()) {
-      std::string result = this->EvaluateDependentExpression(
-        prop, context->LG, context, headTarget, target, &dagChecker);
+      result = this->EvaluateDependentExpression(result, context->LG, context,
+                                                 target, target, &dagChecker);
+      std::string linkedTargetsContent = getLinkedTargetsContent(
+        target, interfacePropertyName, context, &dagChecker);
       if (!linkedTargetsContent.empty()) {
         result += (result.empty() ? "" : ";") + linkedTargetsContent;
       }
-      return result;
     }
-    return prop;
+    return result;
   }
 } targetPropertyNode;
 
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 6e6c917..7c41045 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -22,7 +22,9 @@
 #include "cmCustomCommandGenerator.h"
 #include "cmCustomCommandLines.h"
 #include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionContext.h"
 #include "cmGeneratorExpressionDAGChecker.h"
+#include "cmGeneratorExpressionNode.h"
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
@@ -1141,6 +1143,126 @@
   return this->Target->GetPropertyAsBool(prop);
 }
 
+bool cmGeneratorTarget::MaybeHaveInterfaceProperty(
+  std::string const& prop, cmGeneratorExpressionContext* context) const
+{
+  std::string const key = prop + '@' + context->Config;
+  auto i = this->MaybeInterfacePropertyExists.find(key);
+  if (i == this->MaybeInterfacePropertyExists.end()) {
+    // Insert an entry now in case there is a cycle.
+    i = this->MaybeInterfacePropertyExists.emplace(key, false).first;
+    bool& maybeInterfaceProp = i->second;
+
+    // If this target itself has a non-empty property value, we are done.
+    const char* p = this->GetProperty(prop);
+    maybeInterfaceProp = p && *p;
+
+    // Otherwise, recurse to interface dependencies.
+    if (!maybeInterfaceProp) {
+      cmGeneratorTarget const* headTarget =
+        context->HeadTarget ? context->HeadTarget : this;
+      if (cmLinkInterfaceLibraries const* iface =
+            this->GetLinkInterfaceLibraries(context->Config, headTarget,
+                                            true)) {
+        if (iface->HadHeadSensitiveCondition) {
+          // With a different head target we may get to a library with
+          // this interface property.
+          maybeInterfaceProp = true;
+        } else {
+          // The transitive interface libraries do not depend on the
+          // head target, so we can follow them.
+          for (cmLinkItem const& lib : iface->Libraries) {
+            if (lib.Target &&
+                lib.Target->MaybeHaveInterfaceProperty(prop, context)) {
+              maybeInterfaceProp = true;
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
+  return i->second;
+}
+
+std::string cmGeneratorTarget::EvaluateInterfaceProperty(
+  std::string const& prop, cmGeneratorExpressionContext* context,
+  cmGeneratorExpressionDAGChecker* dagCheckerParent) const
+{
+  std::string result;
+
+  // If the property does not appear transitively at all, we are done.
+  if (!this->MaybeHaveInterfaceProperty(prop, context)) {
+    return result;
+  }
+
+  // Evaluate $<TARGET_PROPERTY:this,prop> as if it were compiled.  This is
+  // a subset of TargetPropertyNode::Evaluate without stringify/parse steps
+  // but sufficient for transitive interface properties.
+  cmGeneratorExpressionDAGChecker dagChecker(context->Backtrace, this, prop,
+                                             nullptr, dagCheckerParent);
+  switch (dagChecker.Check()) {
+    case cmGeneratorExpressionDAGChecker::SELF_REFERENCE:
+      dagChecker.ReportError(
+        context, "$<TARGET_PROPERTY:" + this->GetName() + "," + prop + ">");
+      return result;
+    case cmGeneratorExpressionDAGChecker::CYCLIC_REFERENCE:
+      // No error. We just skip cyclic references.
+      return result;
+    case cmGeneratorExpressionDAGChecker::ALREADY_SEEN:
+      // No error. We have already seen this transitive property.
+      return result;
+    case cmGeneratorExpressionDAGChecker::DAG:
+      break;
+  }
+
+  cmGeneratorTarget const* headTarget =
+    context->HeadTarget ? context->HeadTarget : this;
+
+  if (const char* p = this->GetProperty(prop)) {
+    result = cmGeneratorExpressionNode::EvaluateDependentExpression(
+      p, context->LG, context, headTarget, this, &dagChecker);
+  }
+
+  if (cmLinkInterfaceLibraries const* iface =
+        this->GetLinkInterfaceLibraries(context->Config, headTarget, true)) {
+    for (cmLinkItem const& lib : iface->Libraries) {
+      // Broken code can have a target in its own link interface.
+      // Don't follow such link interface entries so as not to create a
+      // self-referencing loop.
+      if (lib.Target && lib.Target != this) {
+        // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in the
+        // above property and hand-evaluate it as if it were compiled.
+        // Create a context as cmCompiledGeneratorExpression::Evaluate does.
+        cmGeneratorExpressionContext libContext(
+          context->LG, context->Config, context->Quiet, headTarget, this,
+          context->EvaluateForBuildsystem, context->Backtrace,
+          context->Language);
+        std::string libResult = cmGeneratorExpression::StripEmptyListElements(
+          lib.Target->EvaluateInterfaceProperty(prop, &libContext,
+                                                &dagChecker));
+        if (!libResult.empty()) {
+          if (result.empty()) {
+            result = std::move(libResult);
+          } else {
+            result.reserve(result.size() + 1 + libResult.size());
+            result += ";";
+            result += libResult;
+          }
+        }
+        context->HadContextSensitiveCondition =
+          context->HadContextSensitiveCondition ||
+          libContext.HadContextSensitiveCondition;
+        context->HadHeadSensitiveCondition =
+          context->HadHeadSensitiveCondition ||
+          libContext.HadHeadSensitiveCondition;
+      }
+    }
+  }
+
+  return result;
+}
+
 namespace {
 void AddInterfaceEntries(cmGeneratorTarget const* headTarget,
                          std::string const& config, std::string const& prop,
@@ -1152,23 +1274,17 @@
         headTarget->GetLinkImplementationLibraries(config)) {
     for (cmLinkImplItem const& lib : impl->Libraries) {
       if (lib.Target) {
-        std::string uniqueName =
-          headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
-            lib.Target);
-        std::string genex =
-          "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," + prop + ">";
-        cmGeneratorExpression ge(lib.Backtrace);
-        std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
-        cge->SetEvaluateForBuildsystem(true);
-
         EvaluatedTargetPropertyEntry ee(lib, lib.Backtrace);
+        // Pretend $<TARGET_PROPERTY:lib.Target,prop> appeared in our
+        // caller's property and hand-evaluate it as if it were compiled.
+        // Create a context as cmCompiledGeneratorExpression::Evaluate does.
+        cmGeneratorExpressionContext context(
+          headTarget->GetLocalGenerator(), config, false, headTarget,
+          headTarget, true, lib.Backtrace, lang);
         cmSystemTools::ExpandListArgument(
-          cge->Evaluate(headTarget->GetLocalGenerator(), config, false,
-                        headTarget, dagChecker, lang),
+          lib.Target->EvaluateInterfaceProperty(prop, &context, dagChecker),
           ee.Values);
-        if (cge->GetHadContextSensitiveCondition()) {
-          ee.ContextDependent = true;
-        }
+        ee.ContextDependent = context.HadContextSensitiveCondition;
         entries.emplace_back(std::move(ee));
       }
     }
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index e86535d..3874738 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -14,6 +14,7 @@
 #include <set>
 #include <stddef.h>
 #include <string>
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -25,6 +26,9 @@
 class cmSourceFile;
 class cmTarget;
 
+struct cmGeneratorExpressionContext;
+struct cmGeneratorExpressionDAGChecker;
+
 class cmGeneratorTarget
 {
 public:
@@ -674,6 +678,10 @@
 
   class TargetPropertyEntry;
 
+  std::string EvaluateInterfaceProperty(
+    std::string const& prop, cmGeneratorExpressionContext* context,
+    cmGeneratorExpressionDAGChecker* dagCheckerParent) const;
+
   bool HaveInstallTreeRPATH(const std::string& config) const;
 
   bool GetBuildRPATH(const std::string& config, std::string& rpath) const;
@@ -849,6 +857,10 @@
   mutable std::vector<AllConfigSource> AllConfigSources;
   void ComputeAllConfigSources() const;
 
+  mutable std::unordered_map<std::string, bool> MaybeInterfacePropertyExists;
+  bool MaybeHaveInterfaceProperty(std::string const& prop,
+                                  cmGeneratorExpressionContext* context) const;
+
   std::vector<TargetPropertyEntry*> IncludeDirectoriesEntries;
   std::vector<TargetPropertyEntry*> CompileOptionsEntries;
   std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
diff --git a/Source/cmGetCMakePropertyCommand.cxx b/Source/cmGetCMakePropertyCommand.cxx
index fc82fee..8538944 100644
--- a/Source/cmGetCMakePropertyCommand.cxx
+++ b/Source/cmGetCMakePropertyCommand.cxx
@@ -46,7 +46,7 @@
     }
   }
 
-  this->Makefile->AddDefinition(variable, output.c_str());
+  this->Makefile->AddDefinition(variable, output);
 
   return true;
 }
diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx
index a92eb71..98ccb0a 100644
--- a/Source/cmGetDirectoryPropertyCommand.cxx
+++ b/Source/cmGetDirectoryPropertyCommand.cxx
@@ -66,7 +66,7 @@
       return false;
     }
     std::string const& output = dir->GetSafeDefinition(*i);
-    this->Makefile->AddDefinition(variable, output.c_str());
+    this->Makefile->AddDefinition(variable, output);
     return true;
   }
 
@@ -97,9 +97,5 @@
 void cmGetDirectoryPropertyCommand::StoreResult(std::string const& variable,
                                                 const char* prop)
 {
-  if (prop) {
-    this->Makefile->AddDefinition(variable, prop);
-    return;
-  }
-  this->Makefile->AddDefinition(variable, "");
+  this->Makefile->AddDefinition(variable, prop ? prop : "");
 }
diff --git a/Source/cmGetFilenameComponentCommand.cxx b/Source/cmGetFilenameComponentCommand.cxx
index 163b4c8..fc82535 100644
--- a/Source/cmGetFilenameComponentCommand.cxx
+++ b/Source/cmGetFilenameComponentCommand.cxx
@@ -128,9 +128,9 @@
       args[2] == "PATH" ? cmStateEnums::FILEPATH : cmStateEnums::STRING);
   } else {
     if (!programArgs.empty() && !storeArgs.empty()) {
-      this->Makefile->AddDefinition(storeArgs, programArgs.c_str());
+      this->Makefile->AddDefinition(storeArgs, programArgs);
     }
-    this->Makefile->AddDefinition(args.front(), result.c_str());
+    this->Makefile->AddDefinition(args.front(), result);
   }
 
   return true;
diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx
index 039f439..de462ed 100644
--- a/Source/cmGetPropertyCommand.cxx
+++ b/Source/cmGetPropertyCommand.cxx
@@ -121,7 +121,7 @@
     } else {
       output = "NOTFOUND";
     }
-    this->Makefile->AddDefinition(this->Variable, output.c_str());
+    this->Makefile->AddDefinition(this->Variable, output);
   } else if (this->InfoType == OutFullDoc) {
     // Lookup full documentation.
     std::string output;
@@ -132,7 +132,7 @@
     } else {
       output = "NOTFOUND";
     }
-    this->Makefile->AddDefinition(this->Variable, output.c_str());
+    this->Makefile->AddDefinition(this->Variable, output);
   } else if (this->InfoType == OutDefined) {
     // Lookup if the property is defined
     if (this->Makefile->GetState()->GetPropertyDefinition(this->PropertyName,
diff --git a/Source/cmGetSourceFilePropertyCommand.cxx b/Source/cmGetSourceFilePropertyCommand.cxx
index 75879a5..a16076d 100644
--- a/Source/cmGetSourceFilePropertyCommand.cxx
+++ b/Source/cmGetSourceFilePropertyCommand.cxx
@@ -25,7 +25,7 @@
   }
   if (sf) {
     if (args[2] == "LANGUAGE") {
-      this->Makefile->AddDefinition(var, sf->GetLanguage().c_str());
+      this->Makefile->AddDefinition(var, sf->GetLanguage());
       return true;
     }
     const char* prop = nullptr;
diff --git a/Source/cmGetTargetPropertyCommand.cxx b/Source/cmGetTargetPropertyCommand.cxx
index fc0e9c6..07aaf02 100644
--- a/Source/cmGetTargetPropertyCommand.cxx
+++ b/Source/cmGetTargetPropertyCommand.cxx
@@ -75,9 +75,9 @@
     }
   }
   if (prop_exists) {
-    this->Makefile->AddDefinition(var, prop.c_str());
+    this->Makefile->AddDefinition(var, prop);
     return true;
   }
-  this->Makefile->AddDefinition(var, (var + "-NOTFOUND").c_str());
+  this->Makefile->AddDefinition(var, var + "-NOTFOUND");
   return true;
 }
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index ec4107b..7b8ffc5 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -511,7 +511,7 @@
 
   bool fatalError = false;
 
-  mf->AddDefinition("RUN_CONFIGURE", true);
+  mf->AddDefinitionBool("RUN_CONFIGURE", true);
   std::string rootBin = this->CMakeInstance->GetHomeOutputDirectory();
   rootBin += "/CMakeFiles";
 
@@ -525,7 +525,7 @@
   rootBin += cmVersion::GetCMakeVersion();
 
   // set the dir for parent files so they can be used by modules
-  mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR", rootBin.c_str());
+  mf->AddDefinition("CMAKE_PLATFORM_INFO_DIR", rootBin);
 
   if (!this->CMakeInstance->GetIsInTryCompile()) {
     // Keep a mark in the cache to indicate that we've initialized the
@@ -585,8 +585,7 @@
     windowsVersionString << osviex.dwMajorVersion << "."
                          << osviex.dwMinorVersion << "."
                          << osviex.dwBuildNumber;
-    mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION",
-                      windowsVersionString.str().c_str());
+    mf->AddDefinition("CMAKE_HOST_SYSTEM_VERSION", windowsVersionString.str());
 #endif
     // Read the DetermineSystem file
     std::string systemFile = mf->GetModulesFile("CMakeDetermineSystem.cmake");
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index b69dea0..7cfbea6 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -111,7 +111,7 @@
   mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(),
                          "build program to use", cmStateEnums::INTERNAL, true);
 
-  mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp.c_str());
+  mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp);
 
   return true;
 }
diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx
index 7b58389..483d4ab 100644
--- a/Source/cmGlobalMSYSMakefileGenerator.cxx
+++ b/Source/cmGlobalMSYSMakefileGenerator.cxx
@@ -69,9 +69,9 @@
     rc = trc;
   }
   mf->AddDefinition("MSYS", "1");
-  mf->AddDefinition("CMAKE_GENERATOR_CC", gcc.c_str());
-  mf->AddDefinition("CMAKE_GENERATOR_CXX", gxx.c_str());
-  mf->AddDefinition("CMAKE_GENERATOR_RC", rc.c_str());
+  mf->AddDefinition("CMAKE_GENERATOR_CC", gcc);
+  mf->AddDefinition("CMAKE_GENERATOR_CXX", gxx);
+  mf->AddDefinition("CMAKE_GENERATOR_RC", rc);
   this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
 
   if (!mf->IsSet("CMAKE_AR") && !this->CMakeInstance->GetIsInTryCompile() &&
diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx
index e218b4b..d9fc505 100644
--- a/Source/cmGlobalMinGWMakefileGenerator.cxx
+++ b/Source/cmGlobalMinGWMakefileGenerator.cxx
@@ -44,9 +44,9 @@
   if (!trc.empty()) {
     rc = trc;
   }
-  mf->AddDefinition("CMAKE_GENERATOR_CC", gcc.c_str());
-  mf->AddDefinition("CMAKE_GENERATOR_CXX", gxx.c_str());
-  mf->AddDefinition("CMAKE_GENERATOR_RC", rc.c_str());
+  mf->AddDefinition("CMAKE_GENERATOR_CC", gcc);
+  mf->AddDefinition("CMAKE_GENERATOR_CXX", gxx);
+  mf->AddDefinition("CMAKE_GENERATOR_RC", rc);
   this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional);
 }
 
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 55374a4..4a3cadd 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -445,7 +445,7 @@
     this->DefaultPlatformName = "Tegra-Android";
     this->DefaultPlatformToolset = "Default";
     this->NsightTegraVersion = v;
-    mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v.c_str());
+    mf->AddDefinition("CMAKE_VS_NsightTegra_VERSION", v);
   }
 
   return true;
@@ -659,8 +659,7 @@
   if (!this->cmGlobalVisualStudio8Generator::FindMakeProgram(mf)) {
     return false;
   }
-  mf->AddDefinition("CMAKE_VS_MSBUILD_COMMAND",
-                    this->GetMSBuildCommand().c_str());
+  mf->AddDefinition("CMAKE_VS_MSBUILD_COMMAND", this->GetMSBuildCommand());
   return true;
 }
 
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 6509b56..cd48474 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -182,7 +182,7 @@
     mf->DisplayStatus(e.str(), -1);
   }
   mf->AddDefinition("CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION",
-                    this->WindowsTargetPlatformVersion.c_str());
+                    this->WindowsTargetPlatformVersion);
 }
 
 bool cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset(
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index 8764ee4..8401efb 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -121,8 +121,7 @@
   if (!this->cmGlobalVisualStudioGenerator::FindMakeProgram(mf)) {
     return false;
   }
-  mf->AddDefinition("CMAKE_VS_DEVENV_COMMAND",
-                    this->GetDevEnvCommand().c_str());
+  mf->AddDefinition("CMAKE_VS_DEVENV_COMMAND", this->GetDevEnvCommand());
   return true;
 }
 
@@ -268,7 +267,7 @@
                                                    cmMakefile* mf)
 {
   mf->AddDefinition("CMAKE_VS_INTEL_Fortran_PROJECT_VERSION",
-                    this->GetIntelProjectVersion().c_str());
+                    this->GetIntelProjectVersion());
   return this->cmGlobalVisualStudioGenerator::SetSystemName(s, mf);
 }
 
diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx
index 85ddc85..cc6e421 100644
--- a/Source/cmGlobalVisualStudio8Generator.cxx
+++ b/Source/cmGlobalVisualStudio8Generator.cxx
@@ -54,8 +54,7 @@
 void cmGlobalVisualStudio8Generator::AddPlatformDefinitions(cmMakefile* mf)
 {
   if (this->TargetsWindowsCE()) {
-    mf->AddDefinition("CMAKE_VS_WINCE_VERSION",
-                      this->WindowsCEVersion.c_str());
+    mf->AddDefinition("CMAKE_VS_WINCE_VERSION", this->WindowsCEVersion);
   }
 }
 
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index cd0355f..ba541a9 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -57,7 +57,7 @@
   std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
 {
   mf->AddDefinition("CMAKE_VS_PLATFORM_NAME_DEFAULT",
-                    this->DefaultPlatformName.c_str());
+                    this->DefaultPlatformName);
   this->cmGlobalGenerator::EnableLanguage(lang, mf, optional);
 }
 
@@ -69,7 +69,7 @@
   } else if (this->GetPlatformName() == "Itanium") {
     mf->AddDefinition("CMAKE_FORCE_IA64", "TRUE");
   }
-  mf->AddDefinition("CMAKE_VS_PLATFORM_NAME", this->GetPlatformName().c_str());
+  mf->AddDefinition("CMAKE_VS_PLATFORM_NAME", this->GetPlatformName());
   return this->cmGlobalGenerator::SetGeneratorPlatform(p, mf);
 }
 
@@ -488,7 +488,7 @@
   // directly instead of needing a helper module to do it, so we
   // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
   if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
-    mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetVSMakeProgram().c_str());
+    mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetVSMakeProgram());
   }
   return true;
 }
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index d99a906..8f4ae62 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -241,8 +241,7 @@
   // directly instead of needing a helper module to do it, so we
   // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
   if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
-    mf->AddDefinition("CMAKE_MAKE_PROGRAM",
-                      this->GetXcodeBuildCommand().c_str());
+    mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetXcodeBuildCommand());
   }
   return true;
 }
@@ -283,8 +282,7 @@
   }
   this->GeneratorToolset = ts;
   if (!this->GeneratorToolset.empty()) {
-    mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET",
-                      this->GeneratorToolset.c_str());
+    mf->AddDefinition("CMAKE_XCODE_PLATFORM_TOOLSET", this->GeneratorToolset);
   }
   return true;
 }
@@ -293,7 +291,7 @@
   std::vector<std::string> const& lang, cmMakefile* mf, bool optional)
 {
   mf->AddDefinition("XCODE", "1");
-  mf->AddDefinition("XCODE_VERSION", this->VersionString.c_str());
+  mf->AddDefinition("XCODE_VERSION", this->VersionString);
   if (!mf->GetDefinition("CMAKE_CONFIGURATION_TYPES")) {
     mf->AddCacheDefinition(
       "CMAKE_CONFIGURATION_TYPES", "Debug;Release;MinSizeRel;RelWithDebInfo",
diff --git a/Source/cmIncludeGuardCommand.cxx b/Source/cmIncludeGuardCommand.cxx
index 505b07c..3b126b0 100644
--- a/Source/cmIncludeGuardCommand.cxx
+++ b/Source/cmIncludeGuardCommand.cxx
@@ -85,7 +85,7 @@
         status.SetReturnInvoked();
         return true;
       }
-      mf->AddDefinition(includeGuardVar, true);
+      mf->AddDefinitionBool(includeGuardVar, true);
       break;
     case DIRECTORY:
       if (CheckIncludeGuardIsSet(mf, includeGuardVar)) {
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index d891ad8..a61239e 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -767,12 +767,18 @@
         this->IssueCMP0095Warning(newRpath);
         CM_FALLTHROUGH;
       case cmPolicies::OLD:
-        os << indent << "     NEW_RPATH \"" << newRpath << "\")\n";
+        os << indent << "     NEW_RPATH \"" << newRpath << "\"";
         break;
       default:
-        os << indent << "     NEW_RPATH " << escapedNewRpath << ")\n";
+        os << indent << "     NEW_RPATH " << escapedNewRpath;
         break;
     }
+
+    if (this->Target->GetPropertyAsBool("INSTALL_REMOVE_ENVIRONMENT_RPATH")) {
+      os << "\n" << indent << "     INSTALL_REMOVE_ENVIRONMENT_RPATH)\n";
+    } else {
+      os << indent << ")\n";
+    }
   }
 }
 
diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h
index 5b635b5..6450c62 100644
--- a/Source/cmLinkItem.h
+++ b/Source/cmLinkItem.h
@@ -58,6 +58,9 @@
 {
   // Libraries listed in the interface.
   std::vector<cmLinkItem> Libraries;
+
+  // Whether the list depends on a genex referencing the head target.
+  bool HadHeadSensitiveCondition = false;
 };
 
 struct cmLinkInterface : public cmLinkInterfaceLibraries
@@ -84,7 +87,6 @@
   bool LibrariesDone = false;
   bool AllDone = false;
   bool Exists = false;
-  bool HadHeadSensitiveCondition = false;
   const char* ExplicitLibraries = nullptr;
 };
 
diff --git a/Source/cmListCommand.cxx b/Source/cmListCommand.cxx
index a2e665f..d024256 100644
--- a/Source/cmListCommand.cxx
+++ b/Source/cmListCommand.cxx
@@ -222,7 +222,7 @@
     value += varArgsExpanded[item];
   }
 
-  this->Makefile->AddDefinition(variableName, value.c_str());
+  this->Makefile->AddDefinition(variableName, value);
   return true;
 }
 
@@ -246,7 +246,7 @@
     std::string::size_type(listString.empty() || args.empty());
   listString += &";"[offset] + cmJoin(cmMakeRange(args).advance(2), ";");
 
-  this->Makefile->AddDefinition(listName, listString.c_str());
+  this->Makefile->AddDefinition(listName, listString);
   return true;
 }
 
@@ -271,7 +271,7 @@
   listString.insert(0,
                     cmJoin(cmMakeRange(args).advance(2), ";") + &";"[offset]);
 
-  this->Makefile->AddDefinition(listName, listString.c_str());
+  this->Makefile->AddDefinition(listName, listString);
   return true;
 }
 
@@ -299,7 +299,7 @@
       // Ok, assign elements to be removed to the given variables
       for (; !varArgsExpanded.empty() && ai != args.cend(); ++ai) {
         assert(!ai->empty());
-        this->Makefile->AddDefinition(*ai, varArgsExpanded.back().c_str());
+        this->Makefile->AddDefinition(*ai, varArgsExpanded.back());
         varArgsExpanded.pop_back();
       }
       // Undefine the rest variables if the list gets empty earlier...
@@ -308,8 +308,7 @@
       }
     }
 
-    this->Makefile->AddDefinition(listName,
-                                  cmJoin(varArgsExpanded, ";").c_str());
+    this->Makefile->AddDefinition(listName, cmJoin(varArgsExpanded, ";"));
 
   } else if (ai !=
              args.cend()) { // The list is empty, but some args were given
@@ -347,7 +346,7 @@
       auto vi = varArgsExpanded.begin();
       for (; vi != varArgsExpanded.end() && ai != args.cend(); ++ai, ++vi) {
         assert(!ai->empty());
-        this->Makefile->AddDefinition(*ai, vi->c_str());
+        this->Makefile->AddDefinition(*ai, *vi);
       }
       varArgsExpanded.erase(varArgsExpanded.begin(), vi);
       // Undefine the rest variables if the list gets empty earlier...
@@ -356,8 +355,7 @@
       }
     }
 
-    this->Makefile->AddDefinition(listName,
-                                  cmJoin(varArgsExpanded, ";").c_str());
+    this->Makefile->AddDefinition(listName, cmJoin(varArgsExpanded, ";"));
 
   } else if (ai !=
              args.cend()) { // The list is empty, but some args were given
@@ -391,7 +389,7 @@
   if (it != varArgsExpanded.end()) {
     std::ostringstream indexStream;
     indexStream << std::distance(varArgsExpanded.begin(), it);
-    this->Makefile->AddDefinition(variableName, indexStream.str().c_str());
+    this->Makefile->AddDefinition(variableName, indexStream.str());
     return true;
   }
 
@@ -437,7 +435,7 @@
                          args.end());
 
   std::string value = cmJoin(varArgsExpanded, ";");
-  this->Makefile->AddDefinition(listName, value.c_str());
+  this->Makefile->AddDefinition(listName, value);
   return true;
 }
 
@@ -465,7 +463,7 @@
   std::string value =
     cmJoin(cmMakeRange(varArgsExpanded.begin(), varArgsExpanded.end()), glue);
 
-  this->Makefile->AddDefinition(variableName, value.c_str());
+  this->Makefile->AddDefinition(variableName, value);
   return true;
 }
 
@@ -494,7 +492,7 @@
     cmRemoveMatching(varArgsExpanded, cmMakeRange(remBegin, remEnd));
   std::vector<std::string>::const_iterator argsBegin = varArgsExpanded.begin();
   std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
-  this->Makefile->AddDefinition(listName, value.c_str());
+  this->Makefile->AddDefinition(listName, value);
   return true;
 }
 
@@ -515,7 +513,7 @@
 
   std::string value = cmJoin(cmReverseRange(varArgsExpanded), ";");
 
-  this->Makefile->AddDefinition(listName, value.c_str());
+  this->Makefile->AddDefinition(listName, value);
   return true;
 }
 
@@ -540,7 +538,7 @@
   std::vector<std::string>::const_iterator argsBegin = varArgsExpanded.begin();
   std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
 
-  this->Makefile->AddDefinition(listName, value.c_str());
+  this->Makefile->AddDefinition(listName, value);
   return true;
 }
 
@@ -1091,7 +1089,7 @@
   }
 
   this->Makefile->AddDefinition(command.OutputName,
-                                cmJoin(varArgsExpanded, ";").c_str());
+                                cmJoin(varArgsExpanded, ";"));
 
   return true;
 }
@@ -1300,7 +1298,7 @@
   }
 
   std::string value = cmJoin(varArgsExpanded, ";");
-  this->Makefile->AddDefinition(listName, value.c_str());
+  this->Makefile->AddDefinition(listName, value);
   return true;
 }
 
@@ -1349,7 +1347,7 @@
     : size_type(start + length);
   std::vector<std::string> sublist(varArgsExpanded.begin() + start,
                                    varArgsExpanded.begin() + end);
-  this->Makefile->AddDefinition(variableName, cmJoin(sublist, ";").c_str());
+  this->Makefile->AddDefinition(variableName, cmJoin(sublist, ";"));
   return true;
 }
 
@@ -1406,7 +1404,7 @@
   std::vector<std::string>::const_iterator argsBegin = varArgsExpanded.begin();
   std::string value = cmJoin(cmMakeRange(argsBegin, argsEnd), ";");
 
-  this->Makefile->AddDefinition(listName, value.c_str());
+  this->Makefile->AddDefinition(listName, value);
   return true;
 }
 
@@ -1500,6 +1498,6 @@
     std::remove_if(argsBegin, argsEnd, MatchesRegex(regex, includeMatches));
 
   std::string value = cmJoin(cmMakeRange(argsBegin, newArgsEnd), ";");
-  this->Makefile->AddDefinition(listName, value.c_str());
+  this->Makefile->AddDefinition(listName, value);
   return true;
 }
diff --git a/Source/cmLoadCacheCommand.cxx b/Source/cmLoadCacheCommand.cxx
index b1fee8d..3fd7343 100644
--- a/Source/cmLoadCacheCommand.cxx
+++ b/Source/cmLoadCacheCommand.cxx
@@ -153,7 +153,7 @@
       // prefix.
       var = this->Prefix + var;
       if (!value.empty()) {
-        this->Makefile->AddDefinition(var, value.c_str());
+        this->Makefile->AddDefinition(var, value);
       } else {
         this->Makefile->RemoveDefinition(var);
       }
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx
index 78f4f83..5ae660a 100644
--- a/Source/cmLoadCommandCommand.cxx
+++ b/Source/cmLoadCommandCommand.cxx
@@ -230,7 +230,7 @@
   }
 
   // Report what file was loaded for this command.
-  this->Makefile->AddDefinition(reportVar, fullPath.c_str());
+  this->Makefile->AddDefinition(reportVar, fullPath);
 
   // find the init function
   std::string initFuncName = args[0] + "Init";
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index d177278..242ffe3 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -2973,7 +2973,7 @@
   // back to the directory-level values set by the user.
   cmMakefile* mf = this->Makefile;
   cmMakefile::ScopePushPop varScope(mf);
-  mf->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME", targetName.c_str());
+  mf->AddDefinition("MACOSX_BUNDLE_EXECUTABLE_NAME", targetName);
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_INFO_STRING");
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_ICON_FILE");
   cmLGInfoProp(mf, target, "MACOSX_BUNDLE_GUI_IDENTIFIER");
@@ -3012,7 +3012,7 @@
   // back to the directory-level values set by the user.
   cmMakefile* mf = this->Makefile;
   cmMakefile::ScopePushPop varScope(mf);
-  mf->AddDefinition("MACOSX_FRAMEWORK_NAME", targetName.c_str());
+  mf->AddDefinition("MACOSX_FRAMEWORK_NAME", targetName);
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_ICON_FILE");
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_IDENTIFIER");
   cmLGInfoProp(mf, target, "MACOSX_FRAMEWORK_SHORT_VERSION_STRING");
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 3177adc..0fb3237 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -557,8 +557,9 @@
 bool cmMakefile::ReadDependentFile(const std::string& filename,
                                    bool noPolicyScope)
 {
-  this->AddDefinition("CMAKE_PARENT_LIST_FILE",
-                      this->GetDefinition("CMAKE_CURRENT_LIST_FILE"));
+  if (const char* def = this->GetDefinition("CMAKE_CURRENT_LIST_FILE")) {
+    this->AddDefinition("CMAKE_PARENT_LIST_FILE", def);
+  }
   std::string filenametoread = cmSystemTools::CollapseFullPath(
     filename, this->GetCurrentSourceDirectory());
 
@@ -641,9 +642,9 @@
     this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE");
   std::string currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE");
 
-  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread.c_str());
+  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", filenametoread);
   this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
-                      cmSystemTools::GetFilenamePath(filenametoread).c_str());
+                      cmSystemTools::GetFilenamePath(filenametoread));
 
   this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
   this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
@@ -664,10 +665,10 @@
   }
   this->CheckForUnusedVariables();
 
-  this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str());
-  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str());
+  this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile);
+  this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile);
   this->AddDefinition("CMAKE_CURRENT_LIST_DIR",
-                      cmSystemTools::GetFilenamePath(currentFile).c_str());
+                      cmSystemTools::GetFilenamePath(currentFile));
   this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE");
   this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE");
   this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR");
@@ -1535,7 +1536,7 @@
   cmSystemTools::MakeDirectory(filesDir);
 
   assert(cmSystemTools::FileExists(currentStart, true));
-  this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart.c_str());
+  this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentStart);
 
   cmListFile listFile;
   if (!listFile.ParseFile(currentStart.c_str(), this->GetMessenger(),
@@ -1783,12 +1784,8 @@
   }
 }
 
-void cmMakefile::AddDefinition(const std::string& name, const char* value)
+void cmMakefile::AddDefinition(const std::string& name, cm::string_view value)
 {
-  if (!value) {
-    return;
-  }
-
   if (this->VariableInitialized(name)) {
     this->LogUnused("changing definition", name);
   }
@@ -1798,11 +1795,16 @@
   cmVariableWatch* vv = this->GetVariableWatch();
   if (vv) {
     vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
-                         value, this);
+                         value.data(), this);
   }
 #endif
 }
 
+void cmMakefile::AddDefinitionBool(const std::string& name, bool value)
+{
+  this->AddDefinition(name, value ? "ON" : "OFF");
+}
+
 void cmMakefile::AddCacheDefinition(const std::string& name, const char* value,
                                     const char* doc,
                                     cmStateEnums::CacheEntryType type,
@@ -1848,23 +1850,6 @@
   this->StateSnapshot.RemoveDefinition(name);
 }
 
-void cmMakefile::AddDefinition(const std::string& name, bool value)
-{
-  if (this->VariableInitialized(name)) {
-    this->LogUnused("changing definition", name);
-  }
-
-  this->StateSnapshot.SetDefinition(name, value ? "ON" : "OFF");
-
-#ifdef CMAKE_BUILD_WITH_CMAKE
-  cmVariableWatch* vv = this->GetVariableWatch();
-  if (vv) {
-    vv->VariableAccessed(name, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
-                         value ? "ON" : "OFF", this);
-  }
-#endif
-}
-
 void cmMakefile::CheckForUnusedVariables() const
 {
   if (!this->WarnUnused) {
@@ -3285,20 +3270,20 @@
 
 void cmMakefile::SetScriptModeFile(std::string const& scriptfile)
 {
-  this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile.c_str());
+  this->AddDefinition("CMAKE_SCRIPT_MODE_FILE", scriptfile);
 }
 
 void cmMakefile::SetArgcArgv(const std::vector<std::string>& args)
 {
   std::ostringstream strStream;
   strStream << args.size();
-  this->AddDefinition("CMAKE_ARGC", strStream.str().c_str());
+  this->AddDefinition("CMAKE_ARGC", strStream.str());
   // this->MarkVariableAsUsed("CMAKE_ARGC");
 
   for (unsigned int t = 0; t < args.size(); ++t) {
     std::ostringstream tmpStream;
     tmpStream << "CMAKE_ARGV" << t;
-    this->AddDefinition(tmpStream.str(), args[t].c_str());
+    this->AddDefinition(tmpStream.str(), args[t]);
     // this->MarkVariableAsUsed(tmpStream.str().c_str());
   }
 }
@@ -3379,8 +3364,9 @@
 void cmMakefile::EnableLanguage(std::vector<std::string> const& lang,
                                 bool optional)
 {
-  this->AddDefinition("CMAKE_CFG_INTDIR",
-                      this->GetGlobalGenerator()->GetCMakeCFGIntDir());
+  if (const char* def = this->GetGlobalGenerator()->GetCMakeCFGIntDir()) {
+    this->AddDefinition("CMAKE_CFG_INTDIR", def);
+  }
   // If RC is explicitly listed we need to do it after other languages.
   // On some platforms we enable RC implicitly while enabling others.
   // Do not let that look like recursive enable_language(RC).
@@ -4232,7 +4218,7 @@
     std::string const& m = re.match(i);
     if (!m.empty()) {
       std::string const& var = matchVariables[i];
-      this->AddDefinition(var, m.c_str());
+      this->AddDefinition(var, m);
       this->MarkVariableAsUsed(var);
       highest = static_cast<char>('0' + i);
     }
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 1eca18c..18b81d4 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -17,6 +17,8 @@
 #include <unordered_map>
 #include <vector>
 
+#include "cm_string_view.hxx"
+
 #include "cmAlgorithms.h"
 #include "cmFunctionBlocker.h"
 #include "cmListFileCache.h"
@@ -263,18 +265,17 @@
    * Add a variable definition to the build. This variable
    * can be used in CMake to refer to lists, directories, etc.
    */
-  void AddDefinition(const std::string& name, const char* value);
+  void AddDefinition(const std::string& name, cm::string_view value);
+  /**
+   * Add bool variable definition to the build.
+   */
+  void AddDefinitionBool(const std::string& name, bool);
   //! Add a definition to this makefile and the global cmake cache.
   void AddCacheDefinition(const std::string& name, const char* value,
                           const char* doc, cmStateEnums::CacheEntryType type,
                           bool force = false);
 
   /**
-   * Add bool variable definition to the build.
-   */
-  void AddDefinition(const std::string& name, bool);
-
-  /**
    * Remove a variable definition from the build.  This is not valid
    * for cache entries, and will only affect the current makefile.
    */
diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx
index 5213432..0f8aef7 100644
--- a/Source/cmParseArgumentsCommand.cxx
+++ b/Source/cmParseArgumentsCommand.cxx
@@ -75,7 +75,7 @@
 
   for (auto const& iter : singleValArgs) {
     if (!iter.second.empty()) {
-      makefile.AddDefinition(prefix + iter.first, iter.second.c_str());
+      makefile.AddDefinition(prefix + iter.first, iter.second);
     } else {
       makefile.RemoveDefinition(prefix + iter.first);
     }
@@ -84,7 +84,7 @@
   for (auto const& iter : multiValArgs) {
     if (!iter.second.empty()) {
       makefile.AddDefinition(prefix + iter.first,
-                             JoinList(iter.second, parseFromArgV).c_str());
+                             JoinList(iter.second, parseFromArgV));
     } else {
       makefile.RemoveDefinition(prefix + iter.first);
     }
@@ -92,15 +92,14 @@
 
   if (!unparsed.empty()) {
     makefile.AddDefinition(prefix + "UNPARSED_ARGUMENTS",
-                           JoinList(unparsed, parseFromArgV).c_str());
+                           JoinList(unparsed, parseFromArgV));
   } else {
     makefile.RemoveDefinition(prefix + "UNPARSED_ARGUMENTS");
   }
 
   if (!keywordsMissingValues.empty()) {
-    makefile.AddDefinition(
-      prefix + "KEYWORDS_MISSING_VALUES",
-      cmJoin(cmMakeRange(keywordsMissingValues), ";").c_str());
+    makefile.AddDefinition(prefix + "KEYWORDS_MISSING_VALUES",
+                           cmJoin(cmMakeRange(keywordsMissingValues), ";"));
   } else {
     makefile.RemoveDefinition(prefix + "KEYWORDS_MISSING_VALUES");
   }
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index e0f48de..92c80bb 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -286,7 +286,11 @@
          3, 16, 0, cmPolicies::WARN)                                          \
   SELECT(POLICY, CMP0096,                                                     \
          "project() preserves leading zeros in version components.", 3, 16,   \
-         0, cmPolicies::WARN)
+         0, cmPolicies::WARN)                                                 \
+  SELECT(POLICY, CMP0097,                                                     \
+         "ExternalProject_Add with GIT_SUBMODULES \"\" initializes no "       \
+         "submodules.",                                                       \
+         3, 16, 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/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index e3d3bd8..1159ef7 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -45,12 +45,12 @@
     this->Makefile->GetCurrentSourceDirectory().c_str(),
     "Value Computed by CMake", cmStateEnums::STATIC);
 
-  this->Makefile->AddDefinition(
-    "PROJECT_BINARY_DIR", this->Makefile->GetCurrentBinaryDirectory().c_str());
-  this->Makefile->AddDefinition(
-    "PROJECT_SOURCE_DIR", this->Makefile->GetCurrentSourceDirectory().c_str());
+  this->Makefile->AddDefinition("PROJECT_BINARY_DIR",
+                                this->Makefile->GetCurrentBinaryDirectory());
+  this->Makefile->AddDefinition("PROJECT_SOURCE_DIR",
+                                this->Makefile->GetCurrentSourceDirectory());
 
-  this->Makefile->AddDefinition("PROJECT_NAME", projectName.c_str());
+  this->Makefile->AddDefinition("PROJECT_NAME", projectName);
 
   // Set the CMAKE_PROJECT_NAME variable to be the highest-level
   // project name in the tree. If there are two project commands
@@ -60,7 +60,7 @@
   // will work.
   if (!this->Makefile->GetDefinition("CMAKE_PROJECT_NAME") ||
       (this->Makefile->IsRootMakefile())) {
-    this->Makefile->AddDefinition("CMAKE_PROJECT_NAME", projectName.c_str());
+    this->Makefile->AddDefinition("CMAKE_PROJECT_NAME", projectName);
     this->Makefile->AddCacheDefinition(
       "CMAKE_PROJECT_NAME", projectName.c_str(), "Value Computed by CMake",
       cmStateEnums::STATIC);
@@ -258,24 +258,24 @@
 
     std::string vv;
     vv = projectName + "_VERSION";
-    this->Makefile->AddDefinition("PROJECT_VERSION", version_string.c_str());
-    this->Makefile->AddDefinition(vv, version_string.c_str());
+    this->Makefile->AddDefinition("PROJECT_VERSION", version_string);
+    this->Makefile->AddDefinition(vv, version_string);
     vv = projectName + "_VERSION_MAJOR";
     this->Makefile->AddDefinition("PROJECT_VERSION_MAJOR",
-                                  version_components[0].c_str());
-    this->Makefile->AddDefinition(vv, version_components[0].c_str());
+                                  version_components[0]);
+    this->Makefile->AddDefinition(vv, version_components[0]);
     vv = projectName + "_VERSION_MINOR";
     this->Makefile->AddDefinition("PROJECT_VERSION_MINOR",
-                                  version_components[1].c_str());
-    this->Makefile->AddDefinition(vv, version_components[1].c_str());
+                                  version_components[1]);
+    this->Makefile->AddDefinition(vv, version_components[1]);
     vv = projectName + "_VERSION_PATCH";
     this->Makefile->AddDefinition("PROJECT_VERSION_PATCH",
-                                  version_components[2].c_str());
-    this->Makefile->AddDefinition(vv, version_components[2].c_str());
+                                  version_components[2]);
+    this->Makefile->AddDefinition(vv, version_components[2]);
     vv = projectName + "_VERSION_TWEAK";
     this->Makefile->AddDefinition("PROJECT_VERSION_TWEAK",
-                                  version_components[3].c_str());
-    this->Makefile->AddDefinition(vv, version_components[3].c_str());
+                                  version_components[3]);
+    this->Makefile->AddDefinition(vv, version_components[3]);
     // Also, try set top level variables
     TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION", version_string.c_str());
     TopLevelCMakeVarCondSet("CMAKE_PROJECT_VERSION_MAJOR",
@@ -327,14 +327,12 @@
     }
   }
 
-  this->Makefile->AddDefinition("PROJECT_DESCRIPTION", description.c_str());
-  this->Makefile->AddDefinition(projectName + "_DESCRIPTION",
-                                description.c_str());
+  this->Makefile->AddDefinition("PROJECT_DESCRIPTION", description);
+  this->Makefile->AddDefinition(projectName + "_DESCRIPTION", description);
   TopLevelCMakeVarCondSet("CMAKE_PROJECT_DESCRIPTION", description.c_str());
 
-  this->Makefile->AddDefinition("PROJECT_HOMEPAGE_URL", homepage.c_str());
-  this->Makefile->AddDefinition(projectName + "_HOMEPAGE_URL",
-                                homepage.c_str());
+  this->Makefile->AddDefinition("PROJECT_HOMEPAGE_URL", homepage);
+  this->Makefile->AddDefinition(projectName + "_HOMEPAGE_URL", homepage);
   TopLevelCMakeVarCondSet("CMAKE_PROJECT_HOMEPAGE_URL", homepage.c_str());
 
   if (languages.empty()) {
diff --git a/Source/cmQTWrapCPPCommand.cxx b/Source/cmQTWrapCPPCommand.cxx
index 9a764c6..f5852a9 100644
--- a/Source/cmQTWrapCPPCommand.cxx
+++ b/Source/cmQTWrapCPPCommand.cxx
@@ -89,6 +89,6 @@
   }
 
   // Store the final list of source files.
-  this->Makefile->AddDefinition(sourceList, sourceListValue.c_str());
+  this->Makefile->AddDefinition(sourceList, sourceListValue);
   return true;
 }
diff --git a/Source/cmQTWrapUICommand.cxx b/Source/cmQTWrapUICommand.cxx
index 2223e2d..361d7b3 100644
--- a/Source/cmQTWrapUICommand.cxx
+++ b/Source/cmQTWrapUICommand.cxx
@@ -132,7 +132,7 @@
   }
 
   // Store the final list of source files and headers.
-  this->Makefile->AddDefinition(sourceList, sourceListValue.c_str());
-  this->Makefile->AddDefinition(headerList, headerListValue.c_str());
+  this->Makefile->AddDefinition(sourceList, sourceListValue);
+  this->Makefile->AddDefinition(headerList, headerListValue);
   return true;
 }
diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx
index a64ad8c..d0ee4d4 100644
--- a/Source/cmRemoveCommand.cxx
+++ b/Source/cmRemoveCommand.cxx
@@ -52,7 +52,7 @@
   }
 
   // add the definition
-  this->Makefile->AddDefinition(variable, value.c_str());
+  this->Makefile->AddDefinition(variable, value);
 
   return true;
 }
diff --git a/Source/cmSeparateArgumentsCommand.cxx b/Source/cmSeparateArgumentsCommand.cxx
index 28cbdc0..ab4a0c7 100644
--- a/Source/cmSeparateArgumentsCommand.cxx
+++ b/Source/cmSeparateArgumentsCommand.cxx
@@ -69,7 +69,7 @@
     if (const char* def = this->Makefile->GetDefinition(var)) {
       std::string value = def;
       std::replace(value.begin(), value.end(), ' ', ';');
-      this->Makefile->AddDefinition(var, value.c_str());
+      this->Makefile->AddDefinition(var, value);
     }
   } else {
     // Parse the command line.
@@ -97,7 +97,7 @@
         value += si;
       }
     }
-    this->Makefile->AddDefinition(var, value.c_str());
+    this->Makefile->AddDefinition(var, value);
   }
 
   return true;
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index 41555e8..b36878c 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -154,7 +154,7 @@
                                        type, force);
   } else {
     // add the definition
-    this->Makefile->AddDefinition(variable, value.c_str());
+    this->Makefile->AddDefinition(variable, value);
   }
   return true;
 }
diff --git a/Source/cmSourceFileLocation.cxx b/Source/cmSourceFileLocation.cxx
index acacba2..d887627 100644
--- a/Source/cmSourceFileLocation.cxx
+++ b/Source/cmSourceFileLocation.cxx
@@ -146,8 +146,7 @@
   // adding an extension.
   if (!(this->Name.size() > loc.Name.size() &&
         this->Name[loc.Name.size()] == '.' &&
-        cmHasLiteralPrefixImpl(this->Name.c_str(), loc.Name.c_str(),
-                               loc.Name.size()))) {
+        cmHasPrefix(this->Name, loc.Name))) {
     return false;
   }
 
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index 0b12a65..6f9c935 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -308,8 +308,8 @@
     pos->Parent = this->VarTree.Root();
     pos->Root = this->VarTree.Root();
 
-    pos->Vars->Set("CMAKE_SOURCE_DIR", srcDir.c_str());
-    pos->Vars->Set("CMAKE_BINARY_DIR", binDir.c_str());
+    pos->Vars->Set("CMAKE_SOURCE_DIR", srcDir);
+    pos->Vars->Set("CMAKE_BINARY_DIR", binDir);
   }
 
   this->DefineProperty("RULE_LAUNCH_COMPILE", cmProperty::DIRECTORY, "", "",
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index 63bec71..110ec56 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -222,14 +222,14 @@
 }
 
 void cmStateSnapshot::SetDefinition(std::string const& name,
-                                    std::string const& value)
+                                    cm::string_view value)
 {
-  this->Position->Vars->Set(name, value.c_str());
+  this->Position->Vars->Set(name, value);
 }
 
 void cmStateSnapshot::RemoveDefinition(std::string const& name)
 {
-  this->Position->Vars->Set(name, nullptr);
+  this->Position->Vars->Unset(name);
 }
 
 std::vector<std::string> cmStateSnapshot::UnusedKeys() const
@@ -264,7 +264,11 @@
   cmDefinitions::Raise(var, this->Position->Vars, this->Position->Root);
 
   // Now update the definition in the parent scope.
-  this->Position->Parent->Set(var, varDef);
+  if (varDef) {
+    this->Position->Parent->Set(var, varDef);
+  } else {
+    this->Position->Parent->Unset(var);
+  }
   return true;
 }
 
diff --git a/Source/cmStateSnapshot.h b/Source/cmStateSnapshot.h
index c315f48..da39127 100644
--- a/Source/cmStateSnapshot.h
+++ b/Source/cmStateSnapshot.h
@@ -9,6 +9,8 @@
 #include <string>
 #include <vector>
 
+#include "cm_string_view.hxx"
+
 #include "cmLinkedTree.h"
 #include "cmPolicies.h"
 #include "cmStateTypes.h"
@@ -24,7 +26,7 @@
 
   std::string const* GetDefinition(std::string const& name) const;
   bool IsInitialized(std::string const& name) const;
-  void SetDefinition(std::string const& name, std::string const& value);
+  void SetDefinition(std::string const& name, cm::string_view value);
   void RemoveDefinition(std::string const& name);
   std::vector<std::string> UnusedKeys() const;
   std::vector<std::string> ClosureKeys() const;
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 4ad0870..259d92a 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -123,7 +123,7 @@
   std::unique_ptr<cmCryptoHash> hash(cmCryptoHash::New(args[0].c_str()));
   if (hash) {
     std::string out = hash->HashString(args[2]);
-    this->Makefile->AddDefinition(args[1], out.c_str());
+    this->Makefile->AddDefinition(args[1], out);
     return true;
   }
   return false;
@@ -153,7 +153,7 @@
   }
 
   // Store the output in the provided variable.
-  this->Makefile->AddDefinition(outvar, output.c_str());
+  this->Makefile->AddDefinition(outvar, output);
   return true;
 }
 
@@ -179,7 +179,7 @@
     }
   }
   // Store the output in the provided variable.
-  this->Makefile->AddDefinition(outvar, output.c_str());
+  this->Makefile->AddDefinition(outvar, output);
   return true;
 }
 
@@ -216,7 +216,7 @@
   this->Makefile->ConfigureString(args[1], output, atOnly, escapeQuotes);
 
   // Store the output in the provided variable.
-  this->Makefile->AddDefinition(args[2], output.c_str());
+  this->Makefile->AddDefinition(args[2], output);
 
   return true;
 }
@@ -295,7 +295,7 @@
   }
 
   // Store the output in the provided variable.
-  this->Makefile->AddDefinition(outvar, output.c_str());
+  this->Makefile->AddDefinition(outvar, output);
   return true;
 }
 
@@ -342,7 +342,7 @@
   }
 
   // Store the output in the provided variable.
-  this->Makefile->AddDefinition(outvar, output.c_str());
+  this->Makefile->AddDefinition(outvar, output);
   return true;
 }
 
@@ -383,7 +383,7 @@
   }
 
   // Store the output in the provided variable.
-  this->Makefile->AddDefinition(outvar, output.c_str());
+  this->Makefile->AddDefinition(outvar, output);
   return true;
 }
 
@@ -430,7 +430,7 @@
   if (std::string::npos != pos) {
     std::ostringstream s;
     s << pos;
-    this->Makefile->AddDefinition(outvar, s.str().c_str());
+    this->Makefile->AddDefinition(outvar, s.str());
     return true;
   }
 
@@ -505,7 +505,7 @@
   cmsys::SystemTools::ReplaceString(input, matchExpression.c_str(),
                                     replaceExpression.c_str());
 
-  this->Makefile->AddDefinition(variableName, input.c_str());
+  this->Makefile->AddDefinition(variableName, input);
   return true;
 }
 
@@ -538,8 +538,7 @@
     return false;
   }
 
-  this->Makefile->AddDefinition(variableName,
-                                stringValue.substr(begin, end).c_str());
+  this->Makefile->AddDefinition(variableName, stringValue.substr(begin, end));
   return true;
 }
 
@@ -581,7 +580,7 @@
     value = oldValue;
   }
   value += cmJoin(cmMakeRange(args).advance(2), std::string());
-  this->Makefile->AddDefinition(variable, value.c_str());
+  this->Makefile->AddDefinition(variable, value);
   return true;
 }
 
@@ -605,7 +604,7 @@
   if (oldValue) {
     value += oldValue;
   }
-  this->Makefile->AddDefinition(variable, value.c_str());
+  this->Makefile->AddDefinition(variable, value);
   return true;
 }
 
@@ -637,7 +636,7 @@
   // both `CONCAT` and `JOIN` sub-commands.
   std::string value = cmJoin(cmMakeRange(args).advance(varIdx + 1), glue);
 
-  this->Makefile->AddDefinition(variableName, value.c_str());
+  this->Makefile->AddDefinition(variableName, value);
   return true;
 }
 
@@ -653,7 +652,7 @@
   const std::string& variableName = args[2];
 
   this->Makefile->AddDefinition(variableName,
-                                cmSystemTools::MakeCidentifier(input).c_str());
+                                cmSystemTools::MakeCidentifier(input));
   return true;
 }
 
@@ -672,7 +671,7 @@
 
   const std::string& variableName = args[2];
 
-  this->Makefile->AddDefinition(variableName, result.c_str());
+  this->Makefile->AddDefinition(variableName, result);
   return true;
 }
 
@@ -711,8 +710,8 @@
     outLength = endPos - startPos + 1;
   }
 
-  this->Makefile->AddDefinition(
-    variableName, stringValue.substr(startPos, outLength).c_str());
+  this->Makefile->AddDefinition(variableName,
+                                stringValue.substr(startPos, outLength));
   return true;
 }
 
@@ -765,7 +764,7 @@
       break;
   }
 
-  this->Makefile->AddDefinition(variableName, result.c_str());
+  this->Makefile->AddDefinition(variableName, result);
   return true;
 }
 
@@ -871,7 +870,7 @@
 
   cmTimestamp timestamp;
   std::string result = timestamp.CurrentTime(formatString, utcFlag);
-  this->Makefile->AddDefinition(outputVariable, result.c_str());
+  this->Makefile->AddDefinition(outputVariable, result);
 
   return true;
 }
@@ -954,7 +953,7 @@
     uuid = cmSystemTools::UpperCase(uuid);
   }
 
-  this->Makefile->AddDefinition(outputVariable, uuid.c_str());
+  this->Makefile->AddDefinition(outputVariable, uuid);
   return true;
 #else
   std::ostringstream e;
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 723f280..3ba3640 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -282,115 +282,85 @@
   cmSystemTools::Error(m);
 }
 
-bool cmSystemTools::IsInternallyOn(const char* val)
+bool cmSystemTools::IsInternallyOn(cm::string_view val)
 {
-  if (!val) {
-    return false;
-  }
-  std::string v = val;
-  if (v.size() > 4) {
-    return false;
-  }
-
-  for (char& c : v) {
-    c = static_cast<char>(toupper(c));
-  }
-  return v == "I_ON";
+  return (val.size() == 4) &&           //
+    (val[0] == 'I' || val[0] == 'i') && //
+    (val[1] == '_') &&                  //
+    (val[2] == 'O' || val[2] == 'o') && //
+    (val[3] == 'N' || val[3] == 'n');
 }
 
-bool cmSystemTools::IsOn(const char* val)
+bool cmSystemTools::IsOn(cm::string_view val)
 {
-  if (!val) {
-    return false;
+  switch (val.size()) {
+    case 1:
+      return val[0] == '1' || val[0] == 'Y' || val[0] == 'y';
+    case 2:
+      return                                //
+        (val[0] == 'O' || val[0] == 'o') && //
+        (val[1] == 'N' || val[1] == 'n');
+    case 3:
+      return                                //
+        (val[0] == 'Y' || val[0] == 'y') && //
+        (val[1] == 'E' || val[1] == 'e') && //
+        (val[2] == 'S' || val[2] == 's');
+    case 4:
+      return                                //
+        (val[0] == 'T' || val[0] == 't') && //
+        (val[1] == 'R' || val[1] == 'r') && //
+        (val[2] == 'U' || val[2] == 'u') && //
+        (val[3] == 'E' || val[3] == 'e');
+    default:
+      break;
   }
-  /* clang-format off */
-  // "1"
-  if (val[0] == '1' && val[1] == '\0') {
-    return true;
-  }
-  // "ON"
-  if ((val[0] == 'O' || val[0] == 'o') &&
-      (val[1] == 'N' || val[1] == 'n') && val[2] == '\0') {
-    return true;
-  }
-  // "Y", "YES"
-  if ((val[0] == 'Y' || val[0] == 'y') && (val[1] == '\0' || (
-      (val[1] == 'E' || val[1] == 'e') &&
-      (val[2] == 'S' || val[2] == 's') && val[3] == '\0'))) {
-    return true;
-  }
-  // "TRUE"
-  if ((val[0] == 'T' || val[0] == 't') &&
-      (val[1] == 'R' || val[1] == 'r') &&
-      (val[2] == 'U' || val[2] == 'u') &&
-      (val[3] == 'E' || val[3] == 'e') && val[4] == '\0') {
-    return true;
-  }
-  /* clang-format on */
+
   return false;
 }
 
-bool cmSystemTools::IsOn(const std::string& val)
+bool cmSystemTools::IsNOTFOUND(cm::string_view val)
 {
-  return cmSystemTools::IsOn(val.c_str());
+  return (val == "NOTFOUND") || cmHasLiteralSuffix(val, "-NOTFOUND");
 }
 
-bool cmSystemTools::IsNOTFOUND(const char* val)
+bool cmSystemTools::IsOff(cm::string_view val)
 {
-  if (strcmp(val, "NOTFOUND") == 0) {
-    return true;
+  switch (val.size()) {
+    case 0:
+      return true;
+    case 1:
+      return val[0] == '0' || val[0] == 'N' || val[0] == 'n';
+    case 2:
+      return                                //
+        (val[0] == 'N' || val[0] == 'n') && //
+        (val[1] == 'O' || val[1] == 'o');
+    case 3:
+      return                                //
+        (val[0] == 'O' || val[0] == 'o') && //
+        (val[1] == 'F' || val[1] == 'f') && //
+        (val[2] == 'F' || val[2] == 'f');
+    case 5:
+      return                                //
+        (val[0] == 'F' || val[0] == 'f') && //
+        (val[1] == 'A' || val[1] == 'a') && //
+        (val[2] == 'L' || val[2] == 'l') && //
+        (val[3] == 'S' || val[3] == 's') && //
+        (val[4] == 'E' || val[4] == 'e');
+    case 6:
+      return                                //
+        (val[0] == 'I' || val[0] == 'i') && //
+        (val[1] == 'G' || val[1] == 'g') && //
+        (val[2] == 'N' || val[2] == 'n') && //
+        (val[3] == 'O' || val[3] == 'o') && //
+        (val[4] == 'R' || val[4] == 'r') && //
+        (val[5] == 'E' || val[5] == 'e');
+    default:
+      break;
   }
-  return cmHasLiteralSuffix(val, "-NOTFOUND");
-}
 
-bool cmSystemTools::IsOff(const char* val)
-{
-  // ""
-  if (!val || val[0] == '\0') {
-    return true;
-  }
-  /* clang-format off */
-  // "0"
-  if (val[0] == '0' && val[1] == '\0') {
-    return true;
-  }
-  // "OFF"
-  if ((val[0] == 'O' || val[0] == 'o') &&
-      (val[1] == 'F' || val[1] == 'f') &&
-      (val[2] == 'F' || val[2] == 'f') && val[3] == '\0') {
-    return true;
-  }
-  // "N", "NO"
-  if ((val[0] == 'N' || val[0] == 'n') && (val[1] == '\0' || (
-      (val[1] == 'O' || val[1] == 'o') && val[2] == '\0'))) {
-    return true;
-  }
-  // "FALSE"
-  if ((val[0] == 'F' || val[0] == 'f') &&
-      (val[1] == 'A' || val[1] == 'a') &&
-      (val[2] == 'L' || val[2] == 'l') &&
-      (val[3] == 'S' || val[3] == 's') &&
-      (val[4] == 'E' || val[4] == 'e') && val[5] == '\0') {
-    return true;
-  }
-  // "IGNORE"
-  if ((val[0] == 'I' || val[0] == 'i') &&
-      (val[1] == 'G' || val[1] == 'g') &&
-      (val[2] == 'N' || val[2] == 'n') &&
-      (val[3] == 'O' || val[3] == 'o') &&
-      (val[4] == 'R' || val[4] == 'r') &&
-      (val[5] == 'E' || val[5] == 'e') && val[6] == '\0') {
-    return true;
-  }
-  /* clang-format on */
   return cmSystemTools::IsNOTFOUND(val);
 }
 
-bool cmSystemTools::IsOff(const std::string& val)
-{
-  return cmSystemTools::IsOff(val.c_str());
-}
-
 void cmSystemTools::ParseWindowsCommandLine(const char* command,
                                             std::vector<std::string>& args)
 {
@@ -2397,7 +2367,8 @@
 #if defined(CMAKE_USE_ELF_PARSER)
 bool cmSystemTools::ChangeRPath(std::string const& file,
                                 std::string const& oldRPath,
-                                std::string const& newRPath, std::string* emsg,
+                                std::string const& newRPath,
+                                bool removeEnvironmentRPath, std::string* emsg,
                                 bool* changed)
 {
   if (changed) {
@@ -2484,7 +2455,9 @@
 
       // Construct the new value which preserves the part of the path
       // not being changed.
-      rp[rp_count].Value = se[i]->Value.substr(0, prefix_len);
+      if (!removeEnvironmentRPath) {
+        rp[rp_count].Value = se[i]->Value.substr(0, prefix_len);
+      }
       rp[rp_count].Value += newRPath;
       rp[rp_count].Value += se[i]->Value.substr(pos + oldRPath.length());
 
@@ -2570,6 +2543,7 @@
 bool cmSystemTools::ChangeRPath(std::string const& /*file*/,
                                 std::string const& /*oldRPath*/,
                                 std::string const& /*newRPath*/,
+                                bool /*removeEnvironmentRPath*/,
                                 std::string* /*emsg*/, bool* /*changed*/)
 {
   return false;
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index a9c03bd..1962389 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -8,6 +8,7 @@
 #include "cmCryptoHash.h"
 #include "cmDuration.h"
 #include "cmProcessOutput.h"
+#include "cm_string_view.hxx"
 #include "cmsys/Process.h"
 #include "cmsys/SystemTools.hxx" // IWYU pragma: export
 #include <functional>
@@ -149,26 +150,45 @@
    * forced this value. This is not the same as On, but this
    * may be considered as "internally switched on".
    */
-  static bool IsInternallyOn(const char* val);
-  /**
-   * does a string indicate a true or on value ? This is not the same
-   * as ifdef.
-   */
-  static bool IsOn(const char* val);
-  static bool IsOn(const std::string& val);
+  static bool IsInternallyOn(cm::string_view val);
+  static inline bool IsInternallyOn(const char* val)
+  {
+    if (!val) {
+      return false;
+    }
+    return IsInternallyOn(cm::string_view(val));
+  }
 
   /**
-   * does a string indicate a false or off value ? Note that this is
+   * Does a string indicate a true or on value? This is not the same as ifdef.
+   */
+  static bool IsOn(cm::string_view val);
+  inline static bool IsOn(const char* val)
+  {
+    if (!val) {
+      return false;
+    }
+    return IsOn(cm::string_view(val));
+  }
+
+  /**
+   * Does a string indicate a false or off value ? Note that this is
    * not the same as !IsOn(...) because there are a number of
    * ambiguous values such as "/usr/local/bin" a path will result in
    * IsON and IsOff both returning false. Note that the special path
    * NOTFOUND, *-NOTFOUND or IGNORE will cause IsOff to return true.
    */
-  static bool IsOff(const char* val);
-  static bool IsOff(const std::string& val);
+  static bool IsOff(cm::string_view val);
+  inline static bool IsOff(const char* val)
+  {
+    if (!val) {
+      return true;
+    }
+    return IsOff(cm::string_view(val));
+  }
 
   //! Return true if value is NOTFOUND or ends in -NOTFOUND.
-  static bool IsNOTFOUND(const char* value);
+  static bool IsNOTFOUND(cm::string_view val);
   //! Return true if the path is a framework
   static bool IsPathToFramework(const std::string& value);
 
@@ -473,6 +493,7 @@
   /** Try to set the RPATH in an ELF binary.  */
   static bool ChangeRPath(std::string const& file, std::string const& oldRPath,
                           std::string const& newRPath,
+                          bool removeEnvironmentRPath,
                           std::string* emsg = nullptr,
                           bool* changed = nullptr);
 
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index b1a0127..beccfce 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -282,6 +282,7 @@
     initProp("BUILD_RPATH");
     initProp("BUILD_RPATH_USE_ORIGIN");
     initProp("INSTALL_NAME_DIR");
+    initProp("INSTALL_REMOVE_ENVIRONMENT_RPATH");
     initPropValue("INSTALL_RPATH", "");
     initPropValue("INSTALL_RPATH_USE_LINK_PATH", "OFF");
     initProp("INTERPROCEDURAL_OPTIMIZATION");
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index a92c2a0..ed944ac 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -137,7 +137,7 @@
       // now put the output into the variables
       if (!this->RunOutputVariable.empty()) {
         this->Makefile->AddDefinition(this->RunOutputVariable,
-                                      runOutputContents.c_str());
+                                      runOutputContents);
       }
 
       if (!this->OutputVariable.empty()) {
@@ -148,8 +148,7 @@
         if (compileOutput) {
           runOutputContents = compileOutput + runOutputContents;
         }
-        this->Makefile->AddDefinition(this->OutputVariable,
-                                      runOutputContents.c_str());
+        this->Makefile->AddDefinition(this->OutputVariable, runOutputContents);
       }
     }
   }
diff --git a/Source/cmVariableRequiresCommand.cxx b/Source/cmVariableRequiresCommand.cxx
index c02157a..9878ff1 100644
--- a/Source/cmVariableRequiresCommand.cxx
+++ b/Source/cmVariableRequiresCommand.cxx
@@ -42,7 +42,7 @@
   // if reqVar is set to true, but requirementsMet is false , then
   // set reqVar to false.
   if (!reqVar || (!requirementsMet && this->Makefile->IsOn(reqVar))) {
-    this->Makefile->AddDefinition(resultVariable, requirementsMet);
+    this->Makefile->AddDefinitionBool(resultVariable, requirementsMet);
   }
 
   if (!requirementsMet) {
diff --git a/Source/kwsys/CommandLineArguments.cxx b/Source/kwsys/CommandLineArguments.cxx
index a97f7a8..dc9f01d 100644
--- a/Source/kwsys/CommandLineArguments.cxx
+++ b/Source/kwsys/CommandLineArguments.cxx
@@ -67,10 +67,10 @@
 {
 public:
   CommandLineArgumentsInternal()
+    : UnknownArgumentCallback{ KWSYS_NULLPTR }
+    , ClientData{ KWSYS_NULLPTR }
+    , LastArgument{ 0 }
   {
-    this->UnknownArgumentCallback = KWSYS_NULLPTR;
-    this->ClientData = KWSYS_NULLPTR;
-    this->LastArgument = 0;
   }
 
   typedef CommandLineArgumentsVectorOfStrings VectorOfStrings;
diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx
index 5f84b19..3e10765 100644
--- a/Source/kwsys/RegularExpression.cxx
+++ b/Source/kwsys/RegularExpression.cxx
@@ -337,7 +337,6 @@
 {
   const char* scan;
   const char* longest;
-  size_t len;
   int flags;
 
   if (exp == KWSYS_NULLPTR) {
@@ -412,7 +411,7 @@
     //
     if (flags & SPSTART) {
       longest = KWSYS_NULLPTR;
-      len = 0;
+      size_t len = 0;
       for (; scan != KWSYS_NULLPTR; scan = regnext(scan))
         if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
           longest = OPERAND(scan);
diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in
index b7b93f9..ed86418 100644
--- a/Source/kwsys/RegularExpression.hxx.in
+++ b/Source/kwsys/RegularExpression.hxx.in
@@ -407,8 +407,12 @@
  * Create an empty regular expression.
  */
 inline RegularExpression::RegularExpression()
+  : regstart{}
+  , reganch{}
+  , regmust{}
+  , program{ 0 }
+  , progsize{}
 {
-  this->program = 0;
 }
 
 /**
@@ -416,8 +420,12 @@
  * compiles s.
  */
 inline RegularExpression::RegularExpression(const char* s)
+  : regstart{}
+  , reganch{}
+  , regmust{}
+  , program{ 0 }
+  , progsize{}
 {
-  this->program = 0;
   if (s) {
     this->compile(s);
   }
@@ -428,8 +436,12 @@
  * compiles s.
  */
 inline RegularExpression::RegularExpression(const std::string& s)
+  : regstart{}
+  , reganch{}
+  , regmust{}
+  , program{ 0 }
+  , progsize{}
 {
-  this->program = 0;
   this->compile(s);
 }
 
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index ae7a18a..36f24c7 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -3403,11 +3403,7 @@
         out_components.emplace_back(std::move(*i));
       }
     } else if (!i->empty() && *i != cur) {
-#if __cplusplus >= 201103L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201103L)
-      out_components.push_back(std::move(*i));
-#else
-      out_components.push_back(*i);
-#endif
+      out_components.emplace_back(std::move(*i));
     }
   }
 }
@@ -4743,7 +4739,7 @@
       // Test progressively shorter logical-to-physical mappings.
       std::string cwd_str = cwd;
       std::string pwd_path;
-      Realpath(pwd_str.c_str(), pwd_path);
+      Realpath(pwd_str, pwd_path);
       while (cwd_str == pwd_path && cwd_str != pwd_str) {
         // The current pair of paths is a working logical mapping.
         cwd_changed = cwd_str;
@@ -4753,7 +4749,7 @@
         // mapping still works.
         pwd_str = SystemTools::GetFilenamePath(pwd_str);
         cwd_str = SystemTools::GetFilenamePath(cwd_str);
-        Realpath(pwd_str.c_str(), pwd_path);
+        Realpath(pwd_str, pwd_path);
       }
 
       // Add the translation to keep the logical path name.
diff --git a/Tests/CMakeTests/ELFTest.cmake.in b/Tests/CMakeTests/ELFTest.cmake.in
index 4635778..85c2360 100644
--- a/Tests/CMakeTests/ELFTest.cmake.in
+++ b/Tests/CMakeTests/ELFTest.cmake.in
@@ -25,11 +25,36 @@
   # Change the RPATH.
   file(RPATH_CHANGE FILE "${f}"
     OLD_RPATH "/sample/rpath"
-    NEW_RPATH "/rpath/sample")
+    NEW_RPATH "/path1:/path2")
+  set(rpath)
+  file(STRINGS "${f}" rpath REGEX "/path1:/path2" LIMIT_COUNT 1)
+  if(NOT rpath)
+    message(FATAL_ERROR "RPATH not changed in ${f}")
+  endif()
+
+  # Change the RPATH without compiler defined rpath removed
+  file(RPATH_CHANGE FILE "${f}"
+    OLD_RPATH "/path2"
+    NEW_RPATH "/path3")
+  set(rpath)
+  file(STRINGS "${f}" rpath REGEX "/path1:/path3" LIMIT_COUNT 1)
+  if(NOT rpath)
+    message(FATAL_ERROR "RPATH not updated in ${f}")
+  endif()
+
+  # Change the RPATH with compiler defined rpath removed
+  file(RPATH_CHANGE FILE "${f}"
+    OLD_RPATH "/path3"
+    NEW_RPATH "/rpath/sample"
+    INSTALL_REMOVE_ENVIRONMENT_RPATH)
   set(rpath)
   file(STRINGS "${f}" rpath REGEX "/rpath/sample" LIMIT_COUNT 1)
   if(NOT rpath)
-    message(FATAL_ERROR "RPATH not changed in ${f}")
+    message(FATAL_ERROR "RPATH not updated in ${f}")
+  endif()
+  file(STRINGS "${f}" rpath REGEX "/path1" LIMIT_COUNT 1)
+  if(rpath)
+    message(FATAL_ERROR "RPATH not removed in ${f}")
   endif()
 
   # Remove the RPATH.
diff --git a/Tests/ExternalProject/CMakeLists.txt b/Tests/ExternalProject/CMakeLists.txt
index 5adcbd9..093391e 100644
--- a/Tests/ExternalProject/CMakeLists.txt
+++ b/Tests/ExternalProject/CMakeLists.txt
@@ -421,7 +421,7 @@
 
   set(local_git_repo "../../LocalRepositories/GIT-with-submodules")
 
-  set(proj TS1-GIT-no-GIT_SUBMODULES)
+  set(proj TS1-GIT-all-GIT_SUBMODULES)
   ExternalProject_Add(${proj}
     GIT_REPOSITORY "${local_git_repo}"
     CMAKE_GENERATOR "${CMAKE_GENERATOR}"
@@ -435,7 +435,8 @@
   )
   set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
 
-  set(proj TS1-GIT-empty-GIT_SUBMODULES)
+  set(proj TS1-GIT-all-GIT_SUBMODULES-via-CMP0097-OLD)
+  cmake_policy(SET CMP0097 OLD)
   ExternalProject_Add(${proj}
     GIT_REPOSITORY "${local_git_repo}"
     GIT_SUBMODULES ""
@@ -450,6 +451,22 @@
   )
   set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
 
+  set(proj TS1-GIT-no-GIT_SUBMODULES)
+  cmake_policy(SET CMP0097 NEW)
+  ExternalProject_Add(${proj}
+    GIT_REPOSITORY "${local_git_repo}"
+    GIT_SUBMODULES ""
+    CMAKE_GENERATOR "${CMAKE_GENERATOR}"
+    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+               -DWITH_m1:BOOL=OFF
+               -DWITH_m2:BOOL=OFF
+    BUILD_COMMAND ""
+    INSTALL_COMMAND ""
+    DEPENDS "SetupLocalGITRepository"
+            "SetupLocalGITRepositoryWithSubmodules"
+  )
+  set_property(TARGET ${proj} PROPERTY FOLDER "GIT")
+
   set(proj TS1-GIT-some-GIT_SUBMODULES)
   ExternalProject_Add(${proj}
     GIT_REPOSITORY "${local_git_repo}"
diff --git a/Tests/RunCMake/Android/common.cmake b/Tests/RunCMake/Android/common.cmake
index aaa7c89..d96ab86 100644
--- a/Tests/RunCMake/Android/common.cmake
+++ b/Tests/RunCMake/Android/common.cmake
@@ -6,8 +6,6 @@
 endif()
 
 foreach(f
-    "${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX}"
-    "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}g++${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
     "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ar${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
     "${CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX}ld${CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX}"
     )
@@ -51,23 +49,26 @@
   endif()
 endif()
 
-execute_process(
-  COMMAND "${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX}" -dumpmachine
-  OUTPUT_VARIABLE _out OUTPUT_STRIP_TRAILING_WHITESPACE
-  ERROR_VARIABLE _err
-  RESULT_VARIABLE _res
-  )
-if(NOT _res EQUAL 0)
-  message(SEND_ERROR "Failed to run 'gcc -dumpmachine':\n ${_res}")
-endif()
-string(REPLACE "--" "-" _out_check "${_out}")
-if(NOT _out_check STREQUAL "${CMAKE_C_ANDROID_TOOLCHAIN_MACHINE}"
-    AND NOT (_out STREQUAL "arm--linux-android" AND CMAKE_C_ANDROID_TOOLCHAIN_MACHINE STREQUAL "arm-linux-androideabi"))
-  message(SEND_ERROR "'gcc -dumpmachine' produced:\n"
-    " ${_out}\n"
-    "which does not match CMAKE_C_ANDROID_TOOLCHAIN_MACHINE:\n"
-    " ${CMAKE_C_ANDROID_TOOLCHAIN_MACHINE}"
+set(gcc ${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX})
+if(EXISTS "${gcc}")
+  execute_process(
+    COMMAND "${CMAKE_C_ANDROID_TOOLCHAIN_PREFIX}gcc${CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX}" -dumpmachine
+    OUTPUT_VARIABLE _out OUTPUT_STRIP_TRAILING_WHITESPACE
+    ERROR_VARIABLE _err
+    RESULT_VARIABLE _res
     )
+  if(NOT _res EQUAL 0)
+    message(SEND_ERROR "Failed to run 'gcc -dumpmachine':\n ${_res}")
+  endif()
+  string(REPLACE "--" "-" _out_check "${_out}")
+  if(NOT _out_check STREQUAL "${CMAKE_C_ANDROID_TOOLCHAIN_MACHINE}"
+      AND NOT (_out STREQUAL "arm--linux-android" AND CMAKE_C_ANDROID_TOOLCHAIN_MACHINE STREQUAL "arm-linux-androideabi"))
+    message(SEND_ERROR "'gcc -dumpmachine' produced:\n"
+      " ${_out}\n"
+      "which does not match CMAKE_C_ANDROID_TOOLCHAIN_MACHINE:\n"
+      " ${CMAKE_C_ANDROID_TOOLCHAIN_MACHINE}"
+      )
+  endif()
 endif()
 
 if(CMAKE_ANDROID_STL_TYPE STREQUAL "none")
diff --git a/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt b/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt
index 8d0bdc2..a228ccc 100644
--- a/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt
+++ b/Tests/RunCMake/Android/ndk-arm64-v8a-stdout.txt
@@ -1,2 +1,2 @@
 -- Android: Targeting API '[0-9]+' with architecture 'arm64', ABI 'arm64-v8a', and processor 'aarch64'
--- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt
index 3741da3..72ec00e 100644
--- a/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt
+++ b/Tests/RunCMake/Android/ndk-armeabi-arm-stdout.txt
@@ -1,3 +1,3 @@
 -- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi', and processor 'armv5te'
--- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
 .*-- CMAKE_ANDROID_ARM_MODE=1
diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt
index ac2bfd5..8bd87fa 100644
--- a/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt
+++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-neon-stdout.txt
@@ -1,3 +1,3 @@
 -- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a'
--- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
 .*-- CMAKE_ANDROID_ARM_NEON=1
diff --git a/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt b/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt
index 0edb4f7..554548e 100644
--- a/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt
+++ b/Tests/RunCMake/Android/ndk-armeabi-v7a-stdout.txt
@@ -1,3 +1,3 @@
 -- Android: Targeting API '[0-9]+' with architecture 'arm', ABI 'armeabi-v7a', and processor 'armv7-a'
--- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
 .*-- CMAKE_ANDROID_ARM_NEON=0
diff --git a/Tests/RunCMake/Android/ndk-badver-stderr.txt b/Tests/RunCMake/Android/ndk-badver-stderr.txt
index df2c5e6..ce6bc4e 100644
--- a/Tests/RunCMake/Android/ndk-badver-stderr.txt
+++ b/Tests/RunCMake/Android/ndk-badver-stderr.txt
@@ -1,11 +1,12 @@
 ^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\):
-  Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value 'badver' is not one
+  Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value 'badver' is not(
+  supported by this NDK.  It must be 'clang' or not set at all\.| one
   of the allowed forms:
 
     <major>.<minor>       = GCC of specified version
     clang<major>.<minor>  = Clang of specified version
     clang                 = Clang of most recent available version
-
+)
 Call Stack \(most recent call first\):
 .*
   ndk-badver.cmake:1 \(enable_language\)
diff --git a/Tests/RunCMake/Android/ndk-badvernum-stderr.txt b/Tests/RunCMake/Android/ndk-badvernum-stderr.txt
index adacaf1..aec91d9 100644
--- a/Tests/RunCMake/Android/ndk-badvernum-stderr.txt
+++ b/Tests/RunCMake/Android/ndk-badvernum-stderr.txt
@@ -1,4 +1,6 @@
-^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\):
+^CMake Error at .*/Modules/Platform/Android/Determine-Compiler-NDK.cmake:[0-9]+ \(message\):(
+  Android: The CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION value '1.0' is not
+  supported by this NDK.  It must be 'clang' or not set at all.|
   Android: No toolchain for ABI 'armeabi(-v7a)?' found in the NDK:
 
     .*
@@ -6,7 +8,7 @@
   of the version specified by CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION:
 
     1\.0
-
+)
 Call Stack \(most recent call first\):
 .*
   ndk-badvernum.cmake:1 \(enable_language\)
diff --git a/Tests/RunCMake/Android/ndk-mips-stdout.txt b/Tests/RunCMake/Android/ndk-mips-stdout.txt
index c744683..8ce544d 100644
--- a/Tests/RunCMake/Android/ndk-mips-stdout.txt
+++ b/Tests/RunCMake/Android/ndk-mips-stdout.txt
@@ -1,2 +1,2 @@
 -- Android: Targeting API '[0-9]+' with architecture 'mips', ABI 'mips', and processor 'mips'
--- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-mips64-stdout.txt b/Tests/RunCMake/Android/ndk-mips64-stdout.txt
index 839ddfd..1d7edea 100644
--- a/Tests/RunCMake/Android/ndk-mips64-stdout.txt
+++ b/Tests/RunCMake/Android/ndk-mips64-stdout.txt
@@ -1,2 +1,2 @@
 -- Android: Targeting API '[0-9]+' with architecture 'mips64', ABI 'mips64', and processor 'mips64'
--- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-x86-stdout.txt b/Tests/RunCMake/Android/ndk-x86-stdout.txt
index 2dbb2f0..8d710fe 100644
--- a/Tests/RunCMake/Android/ndk-x86-stdout.txt
+++ b/Tests/RunCMake/Android/ndk-x86-stdout.txt
@@ -1,2 +1,2 @@
 -- Android: Targeting API '[0-9]+' with architecture 'x86', ABI 'x86', and processor 'i686'
--- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/Android/ndk-x86_64-stdout.txt b/Tests/RunCMake/Android/ndk-x86_64-stdout.txt
index a7ae91d..695a088 100644
--- a/Tests/RunCMake/Android/ndk-x86_64-stdout.txt
+++ b/Tests/RunCMake/Android/ndk-x86_64-stdout.txt
@@ -1,2 +1,2 @@
 -- Android: Targeting API '[0-9]+' with architecture 'x86_64', ABI 'x86_64', and processor 'x86_64'
--- Android: Selected (Clang toolchain '[^']+' with )?GCC toolchain '[^']+'
+-- Android: Selected (unified Clang toolchain|(Clang toolchain '[^']+' with )?GCC toolchain '[^']+')
diff --git a/Tests/RunCMake/find_program/RelAndAbsPath.cmake b/Tests/RunCMake/find_program/RelAndAbsPath.cmake
index 3c60a20..6b61980 100644
--- a/Tests/RunCMake/find_program/RelAndAbsPath.cmake
+++ b/Tests/RunCMake/find_program/RelAndAbsPath.cmake
@@ -10,7 +10,6 @@
 
 strip_windows_path_prefix("${CMAKE_CURRENT_SOURCE_DIR}" srcdir)
 
-file(MAKE_DIRECTORY "tmp${srcdir}")
 configure_file(testCWD "tmp${srcdir}/testNoSuchFile" COPYONLY)
 
 find_program(PROG_ABS