Merge branch 'release-4.1'
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cccd68c..f2f4772 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -140,6 +140,13 @@
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
+l:clazy-fedora42:
+    extends:
+        - .fedora42_clazy
+        - .cmake_build_linux
+        - .linux_x86_64_tags
+        - .run_automatically
+
 # Linux builds
 
 b:centos7-x86_64:
@@ -806,6 +813,13 @@
         CMAKE_CI_BUILD_NAME: oneapi2025.1.0_makefiles
         CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2025.1.0-rocky9
 
+t:oneapi2025.2.0-makefiles:
+    extends:
+        - .cmake_test_linux_inteloneapi_makefiles
+    variables:
+        CMAKE_CI_BUILD_NAME: oneapi2025.2.0_makefiles
+        CMAKE_CI_INTELCOMPILER_IMAGE_TAG: 2025.2.0-rocky9
+
 b:linux-x86_64-package:
     extends:
         - .linux_package
@@ -941,16 +955,6 @@
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
-b:macos-arm64-curl:
-    extends:
-        - .macos_arm64_curl
-        - .cmake_build_macos
-        - .cmake_build_artifacts
-        - .macos_arm64_tags
-        - .run_manually
-    variables:
-        CMAKE_CI_JOB_NIGHTLY: "true"
-
 b:macos-arm64-pch:
     extends:
         - .macos_arm64_pch
@@ -998,17 +1002,6 @@
         CMAKE_CI_JOB_NIGHTLY: "true"
         CMAKE_CI_JOB_NIGHTLY_NINJA: "true"
 
-t:macos-arm64-curl:
-    extends:
-        - .macos_arm64_curl
-        - .cmake_test_macos
-        - .macos_arm64_tags
-        - .run_dependent
-    needs:
-        - b:macos-arm64-curl
-    variables:
-        CMAKE_CI_JOB_NIGHTLY: "true"
-
 b:macos-x86_64-makefiles:
     extends:
         - .macos_x86_64_makefiles
diff --git a/.gitlab/.gitignore b/.gitlab/.gitignore
index ef38d5f..848d72f 100644
--- a/.gitlab/.gitignore
+++ b/.gitlab/.gitignore
@@ -2,6 +2,7 @@
 /5.15.1-0-202009071110*
 /bcc*
 /cmake*
+/emsdk
 /iar
 /intel
 /ispc*
diff --git a/.gitlab/ci/configure_debian12_makefiles_clang.cmake b/.gitlab/ci/configure_debian12_makefiles_clang.cmake
index 9bd6275..fa92973 100644
--- a/.gitlab/ci/configure_debian12_makefiles_clang.cmake
+++ b/.gitlab/ci/configure_debian12_makefiles_clang.cmake
@@ -4,6 +4,7 @@
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_IAR_TOOLCHAINS "/opt/iarsystems" CACHE PATH "")
   set(CMake_TEST_TICLANG_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/ticlang" CACHE PATH "")
+  set(CMake_TEST_Emscripten_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/emsdk/upstream/emscripten" CACHE PATH "")
 endif()
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_debian12_ninja_clang.cmake b/.gitlab/ci/configure_debian12_ninja_clang.cmake
index 1a8e192..7f45fa9 100644
--- a/.gitlab/ci/configure_debian12_ninja_clang.cmake
+++ b/.gitlab/ci/configure_debian12_ninja_clang.cmake
@@ -1,6 +1,7 @@
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
   set(CMake_TEST_IAR_TOOLCHAINS "/opt/iarsystems" CACHE PATH "")
   set(CMake_TEST_TICLANG_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/ticlang" CACHE PATH "")
+  set(CMake_TEST_Emscripten_TOOLCHAINS "$ENV{CI_PROJECT_DIR}/.gitlab/emsdk/upstream/emscripten" CACHE PATH "")
 endif()
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")
diff --git a/.gitlab/ci/configure_fedora42_clazy.cmake b/.gitlab/ci/configure_fedora42_clazy.cmake
new file mode 100644
index 0000000..04f3640
--- /dev/null
+++ b/.gitlab/ci/configure_fedora42_clazy.cmake
@@ -0,0 +1,5 @@
+set(configure_no_sccache 1)
+set(CMake_QT_MAJOR_VERSION "5" CACHE STRING "")
+set(CMAKE_USE_SYSTEM_JSONCPP ON CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_fedora42_common.cmake")
diff --git a/.gitlab/ci/configure_macos_arm64_curl.cmake b/.gitlab/ci/configure_macos_arm64_curl.cmake
deleted file mode 100644
index 73263cb..0000000
--- a/.gitlab/ci/configure_macos_arm64_curl.cmake
+++ /dev/null
@@ -1,10 +0,0 @@
-# Build with our vendored curl instead of the default system version.
-set(CMAKE_USE_SYSTEM_CURL "OFF" CACHE BOOL "")
-
-set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
-set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
-set(CMake_TEST_TLS_VERSION "1.2" CACHE STRING "")
-set(CMake_TEST_TLS_VERSION_URL_BAD "https://badtls-v1-1.kitware.com:8011" CACHE STRING "")
-
-include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
-include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
diff --git a/.gitlab/ci/configure_windows_msvc_v71_nmake.cmake b/.gitlab/ci/configure_windows_msvc_v71_nmake.cmake
index 166690a..78587a9 100644
--- a/.gitlab/ci/configure_windows_msvc_v71_nmake.cmake
+++ b/.gitlab/ci/configure_windows_msvc_v71_nmake.cmake
@@ -1 +1,3 @@
+set(CMake_TEST_PrecompileHeaders_TIMEOUT 1000 CACHE STRING "")
+
 include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_msvc_common.cmake")
diff --git a/.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake b/.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake
index 3fb894c..2771e3f 100644
--- a/.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake
+++ b/.gitlab/ci/configure_windows_vs2022_x64_ninja.cmake
@@ -1,4 +1,4 @@
-set(CMake_TEST_C_STANDARDS "90;99;11;17" CACHE STRING "")
+set(CMake_TEST_C_STANDARDS "90;99;11;17;23" CACHE STRING "")
 set(CMake_TEST_CXX_STANDARDS "98;11;14;17;20;23" CACHE STRING "")
 
 if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
diff --git a/.gitlab/ci/docker/fedora42/deps_packages.lst b/.gitlab/ci/docker/fedora42/deps_packages.lst
index 5682514..c3f8768 100644
--- a/.gitlab/ci/docker/fedora42/deps_packages.lst
+++ b/.gitlab/ci/docker/fedora42/deps_packages.lst
@@ -38,6 +38,7 @@
 
 # Install lint tools.
 clang-analyzer
+clazy
 codespell
 
 # Tools needed for the test suite.
diff --git a/.gitlab/ci/emsdk-env.sh b/.gitlab/ci/emsdk-env.sh
new file mode 100644
index 0000000..c62e0e7
--- /dev/null
+++ b/.gitlab/ci/emsdk-env.sh
@@ -0,0 +1,3 @@
+.gitlab/ci/emsdk.sh
+. .gitlab/emsdk/emsdk_env.sh
+em++ --version
diff --git a/.gitlab/ci/emsdk.sh b/.gitlab/ci/emsdk.sh
new file mode 100755
index 0000000..0a798a2
--- /dev/null
+++ b/.gitlab/ci/emsdk.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+set -e
+
+case "$(uname -s)-$(uname -m)" in
+    Linux-x86_64)
+        ;;
+    *)
+        echo "Unrecognized platform $(uname -s)-$(uname -m)"
+        exit 1
+        ;;
+esac
+
+cd .gitlab
+
+version=4.0.9
+dirname="emsdk-$version"
+filename="$dirname.tar.gz"
+curl -OJL "https://github.com/emscripten-core/emsdk/archive/refs/tags/$version.tar.gz"
+tar xzf "$filename"
+mv "$dirname" emsdk
+emsdk/emsdk install "$version"
+emsdk/emsdk activate "$version"
+
+rm -f "$filename"
diff --git a/.gitlab/ci/env_debian12_makefiles_clang.sh b/.gitlab/ci/env_debian12_makefiles_clang.sh
index e4ee249..11f0745 100644
--- a/.gitlab/ci/env_debian12_makefiles_clang.sh
+++ b/.gitlab/ci/env_debian12_makefiles_clang.sh
@@ -1,6 +1,7 @@
 if test "$CMAKE_CI_NIGHTLY" = "true"; then
   source .gitlab/ci/iar-env.sh
   source .gitlab/ci/ticlang-env.sh
+  source .gitlab/ci/emsdk-env.sh
 fi
 
 export CC=/usr/bin/clang-15
diff --git a/.gitlab/ci/env_debian12_ninja_clang.sh b/.gitlab/ci/env_debian12_ninja_clang.sh
index e4ee249..11f0745 100644
--- a/.gitlab/ci/env_debian12_ninja_clang.sh
+++ b/.gitlab/ci/env_debian12_ninja_clang.sh
@@ -1,6 +1,7 @@
 if test "$CMAKE_CI_NIGHTLY" = "true"; then
   source .gitlab/ci/iar-env.sh
   source .gitlab/ci/ticlang-env.sh
+  source .gitlab/ci/emsdk-env.sh
 fi
 
 export CC=/usr/bin/clang-15
diff --git a/.gitlab/ci/env_fedora42_clazy.sh b/.gitlab/ci/env_fedora42_clazy.sh
new file mode 100644
index 0000000..007c52d
--- /dev/null
+++ b/.gitlab/ci/env_fedora42_clazy.sh
@@ -0,0 +1,25 @@
+export CC=/usr/bin/clang
+export CXX=/usr/bin/clazy
+export CLANGXX=/usr/bin/clang++
+
+export CLAZY_CHECKS="level2\
+,no-base-class-event\
+,no-connect-3arg-lambda\
+,no-connect-by-name\
+,no-container-inside-loop\
+,no-copyable-polymorphic\
+,no-ctor-missing-parent-argument\
+,no-function-args-by-ref\
+,no-missing-qobject-macro\
+,no-non-pod-global-static\
+,no-old-style-connect\
+,no-qproperty-without-notify\
+,no-qstring-allocations\
+,no-range-loop-detach\
+,no-range-loop-reference\
+,no-reserve-candidates\
+,no-rule-of-three\
+,no-rule-of-two-soft\
+,no-static-pmf\
+,no-strict-iterators\
+"
diff --git a/.gitlab/ci/env_macos_x86_64_makefiles.sh b/.gitlab/ci/env_macos_x86_64_makefiles.sh
index 7496372..dca8dd7 100644
--- a/.gitlab/ci/env_macos_x86_64_makefiles.sh
+++ b/.gitlab/ci/env_macos_x86_64_makefiles.sh
@@ -2,3 +2,4 @@
 if test "$CMAKE_CI_NIGHTLY" = "true"; then
   source .gitlab/ci/ispc-env.sh
 fi
+export CFLAGS=-Wstrict-prototypes
diff --git a/.gitlab/ci/iar-env.sh b/.gitlab/ci/iar-env.sh
index 9ec7494..39a5580 100644
--- a/.gitlab/ci/iar-env.sh
+++ b/.gitlab/ci/iar-env.sh
@@ -1,10 +1,10 @@
 files='
-bxarm-9.60.4.deb
+bxarm-9.70.1.deb
 bxavr-8.10.2.deb
 bxrh850-3.10.2.deb
-bxriscv-3.30.1.deb
-bxrl78-5.10.3.deb
-bxrx-5.10.1.deb
+bxriscv-3.40.1.deb
+bxrl78-5.20.1.deb
+bxrx-5.20.1.deb
 '
 for f in $files; do
   # This URL is only visible inside of Kitware's network.
@@ -12,12 +12,12 @@
 done
 
 echo '
-cd92a136bc9bbb1e713121cb407131b54250d2ae30809df3cd752c6383e1878f  bxarm-9.60.4.deb
+3b16748e560ab8fa3ffe6d6807186ac706134c78bc9db911112ab3ee67c7b997  bxarm-9.70.1.deb
 4a1065291952a23a8bfbbaa4eb36ca49b0af8653b8faab34ce955d9d48d64506  bxavr-8.10.2.deb
 b14085a0f21750c58168125d3cece2e3fcbd4c6495c652b5e65b6637bac0ac31  bxrh850-3.10.2.deb
-517e18dffdd4345f97c480b5128c7feea25ec1c3f06e62d8e2e6808c401d514a  bxriscv-3.30.1.deb
-3deca7f6afd5f47684464ad748334ab0690097a109d9c680603450074fc32ccf  bxrl78-5.10.3.deb
-260e592c48cbaf902b13bdb2feeeba83068978131fcb5c027dab17e715dec7e7  bxrx-5.10.1.deb
+2e7de58a3aad43ef4199b811edd4dae9c4bff633376393f12fcb77ca27aba831  bxriscv-3.40.1.deb
+6a2b6163dd971635715f49cb072c853e5de55d2b0089f319a6a9f6db540af4bd  bxrl78-5.20.1.deb
+059667a53b6683b1b09b7842d71e784c04bc2376734421c3a628acdbc6bef9e3  bxrx-5.20.1.deb
 ' > bxdebs.sha256sum
 sha256sum --check bxdebs.sha256sum
 
diff --git a/.gitlab/ci/iar.ps1 b/.gitlab/ci/iar.ps1
index 2034fa2..4c1093d 100644
--- a/.gitlab/ci/iar.ps1
+++ b/.gitlab/ci/iar.ps1
@@ -7,12 +7,12 @@
 $iar_dir = New-Item -Force -ItemType Directory -Path "$outdir\iar"
 
 $files = @{
-    "bxarm-9.60.4.11196-1.zip" = "0DE5F610D0FA3A6513C856BC2403A84D5277F1F6D0D65A6022D1FD745BC4AF6A"
+    "bxarm-9.70.1.13552-1.zip" = "866792FA6881C28610558E87EE02A45752CC06E7550FB57682720CDC300DA0B7"
     "BXAVR-8102-1.zip"         = "862EFD23531854506070D5647F9B32197B80E5A727304BFBD8E386A3DAADF093"
     "BXRH850-3102-1.zip"       = "8D1D009A0D138C7CA8431316123CB85CE1B41319A68B997F90D2E338CD469C7F"
-    "BXRISCV-3301-1.zip"       = "59FF23F7B98EE72567A23942DE799AF137791A19BFEC102B2A59821FABBCA55A"
-    "BXRL78-5103-1.zip"        = "00398E7197735A7B0A4310BF906808E883548814475C12D6EF2C03388F77E6A7"
-    "BXRX-5101-1.zip"          = "D63E95ECD454B4998946C2D9DC1CB6CEF69CE15524C11A123263E6A8E88D9899"
+    "BXRISCV-3401-1.zip"       = "633F9BF64429923B0C478FB8ED0C47B3A67BC9B23DD9A2851DE66AC70DA64E06"
+    "bxrl78-5.20.1.2826-1.zip" = "71E981EC18C5BC031A356D89C4D6579DF0B0EF9EB34AB3B46A48DA3F3737C2D4"
+    "bxrx-5.20.1.6541-1.zip"   = "C000B333618A253482DCCB8F06CB902F6D9D0B7D554B863175D316004FBFFC82"
 }
 
 foreach ($f in $files.GetEnumerator()) {
diff --git a/.gitlab/ci/repackage/iar.ps1 b/.gitlab/ci/repackage/iar.ps1
index 5a8c1e5..eb140cd 100644
--- a/.gitlab/ci/repackage/iar.ps1
+++ b/.gitlab/ci/repackage/iar.ps1
@@ -23,12 +23,26 @@
   "arm/config/flashloader"
   "arm/drivers"
   "arm/src"
+  "riscv/config/debugger"
+  "riscv/config/flashloader"
+  "riscv/drivers"
+  "riscv/src"
+  "rl78/config/debugger"
+  "rl78/config/flashloader"
+  "rl78/drivers"
+  "rl78/src"
+  "rx/config/debugger"
+  "rx/config/flashloader"
+  "rx/drivers"
+  "rx/src"
   )
 
 Write-Host "Installing to: $package_dir"
 Start-Process -Wait -FilePath "$installer_file" -ArgumentList "/hide_usd /autoinstall/$package_dir"
 foreach ($p in $exclude) {
-    Remove-Item "$package_dir/$p" -Recurse -Force
+    if (Test-Path "$package_dir/$p") {
+        Remove-Item "$package_dir/$p" -Recurse -Force
+    }
 }
 
 @"
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 9f08416..4436240 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -83,7 +83,7 @@
 ### Fedora
 
 .fedora42:
-    image: "kitware/cmake:ci-fedora42-x86_64-2025-04-22"
+    image: "kitware/cmake:ci-fedora42-x86_64-2025-07-22"
 
     variables:
         GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes"
@@ -115,6 +115,15 @@
         CTEST_NO_WARNINGS_ALLOWED: 1
         CMAKE_CI_NO_INSTALL: 1
 
+.fedora42_clazy:
+    extends: .fedora42
+
+    variables:
+        CMAKE_CONFIGURATION: fedora42_clazy
+        CMAKE_CI_BUILD_TYPE: Debug
+        CTEST_NO_WARNINGS_ALLOWED: 1
+        CMAKE_CI_NO_INSTALL: 1
+
 .fedora42_sphinx:
     extends: .fedora42
 
diff --git a/.gitlab/os-macos.yml b/.gitlab/os-macos.yml
index 66ee593..41a417d 100644
--- a/.gitlab/os-macos.yml
+++ b/.gitlab/os-macos.yml
@@ -49,13 +49,6 @@
         CMAKE_CI_IN_SYMLINK_TREE: 1
         CMAKE_CI_BUILD_DIR: "real_work/work/build"
 
-.macos_arm64_curl:
-    extends: .macos_build
-
-    variables:
-        CMAKE_CONFIGURATION: macos_arm64_curl
-        CTEST_NO_WARNINGS_ALLOWED: 1
-
 .macos_arm64_pch:
     extends: .macos_arm64_ninja
 
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 8b6d940..a9cb573 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -39,6 +39,7 @@
                 CMakeLib/testCTestResourceSpec_data/spec13
               | RunCMake/CTestResourceAllocation/invalid
               )\.json
+      - id: check-toml
       - id: check-yaml
       - id: end-of-file-fixer
         # NOTE Exclude tests directory: some test files have no
@@ -102,13 +103,14 @@
       - id: rst-inline-touching-normal
 
   - repo: https://github.com/codespell-project/codespell
-    rev: v2.4.0
+    rev: v2.4.1
     hooks:
       - id: codespell
         stages: [commit-msg, pre-commit]
 
-  - repo: https://github.com/crate-ci/typos
-    rev: v1.30.0
+    # NOTE See BUG https://github.com/crate-ci/typos/issues/390
+  - repo: https://github.com/adhtruong/mirrors-typos
+    rev: v1.33.1
     hooks:
       - id: typos
         # NOTE Override hook's default args to prevent automatic
diff --git a/.typos.toml b/.typos.toml
index 5ad2245..42cf331 100644
--- a/.typos.toml
+++ b/.typos.toml
@@ -5,10 +5,10 @@
 check-file = true
 check-filename = true
 extend-ignore-re = [
-    # NOTE Allow to mark a block of text to exclude from spellchecking
-    "(?s)(#|/(/|\\*)|\\.\\.)\\s*(NOQA|noqa):? spellcheck(: *|=| +)off.*?\\n\\s*(#|/(/|\\*)|\\.\\.)\\s*(NOQA|noqa):? spellcheck(: *|=| +)on"
+    # NOTE Allow to mark block of text to exclude from spellchecking inside C++ or hash-style comments (CMake,Python,&etc.)
+    "(?s)(#|//)\\s*(NOQA|noqa):? spellcheck(: *|=| +)off.*?\\n\\s*(#|//)\\s*(NOQA|noqa):? spellcheck(: *|=| +)on"
     # NOTE Allow to mark a line to exclude from spellchecking
-  , "(?Rm)^.*(#|/(/|\\*)|\\.\\.)\\s*(NOQA|noqa):? spellcheck(: *|=| +)disable-line$"
+  , "(?Rm)^.*(#|//)\\s*(NOQA|noqa):? spellcheck(: *|=| +)disable-line$"
     # NOTE Stop checking from this line to the end of file
     # This line is a marker added by Git to the `COMMIT_EDITMSG`.
   , "(?sm)^# ------------------------ >8 ------------------------$.*"
@@ -18,7 +18,7 @@
 # `extend-ignore-identifiers-re` to this section,
 # please also modify the `.gitlab/ci/typos.bash`
 # script accordingly.
-#extend-ignore-identifiers-re=["\\b[0-9a-f]{10}\\b"]
+#extend-ignore-identifiers-re=["\\b[0-9a-f]{8,12}\\b"]
 
 # Add repo-wide false positives here in the form of `word = "word"`.
 # Check the manual for details.
@@ -34,31 +34,8 @@
 restat = "restat"
 # SpectreMitigation
 Spectre = "Spectre"
-
-[type.cmake.extend-identifiers]
-COMMANDs = "COMMANDs"
-xCOMMANDx = "xCOMMANDx"
-TYPEs = "TYPEs"
-
-[type.cmake.extend-words]
-# Some compiler's options trigger false-positives
-Fo = "Fo"
-ot = "ot"
-# Part of compiler executable name, e.g., `arm-unknown-nto-qnx6`, but also could be in a literal string.
-nto = "nto"
-
-[type.cpp.extend-identifiers]
-APPENDed = "APPENDed"
-
-[type.json.extend-identifiers]
-# Some compiler options from `Templates/MSBuild/FlagTables/*.json` trigger too many false-positives.
-Fo = "Fo"
-fo = "fo"
-Ot = "Ot"
-SEH = "SEH"
-
-[type.py.extend-identifiers]
-typ = "typ"
+# Identifier used in source code (`GlobalTargetInfo`)
+gti = "gti"
 
 [files]
 ignore-hidden = false
@@ -77,3 +54,38 @@
     # FIXME: Fix spelling typos in tests.  Exclude for now.
   , "Tests"
   ]
+
+# BEGIN Type-specific settings
+[type.cmake.extend-identifiers]
+COMMANDs = "COMMANDs"
+xCOMMANDx = "xCOMMANDx"
+TYPEs = "TYPEs"
+
+[type.cmake.extend-words]
+# Some compiler's options trigger false-positives
+Fo = "Fo"
+ot = "ot"
+# Part of compiler executable name, e.g., `arm-unknown-nto-qnx6`, but also could be in a literal string.
+nto = "nto"
+
+[type.cpp.extend-identifiers]
+APPENDed = "APPENDed"
+setp = "setp"
+setp_ = "setp_"
+
+[type.json.extend-identifiers]
+# Some compiler options from `Templates/MSBuild/FlagTables/*.json` trigger too many false-positives.
+Fo = "Fo"
+fo = "fo"
+Ot = "Ot"
+SEH = "SEH"
+
+[type.py.extend-identifiers]
+typ = "typ"
+
+[type.rst]
+extend-ignore-re = [
+    # NOTE Allow to mark block of text to exclude from spellchecking as RST comments
+    "(?s)\\.\\.\\s+(NOQA|noqa):? spellcheck(: *|=| +)off.*?\\n\\.\\.\\s+(NOQA|noqa):? spellcheck(: *|=| +)on"
+  ]
+# END Type-specific settings
diff --git a/Auxiliary/vim/cmake.vim.in b/Auxiliary/vim/cmake.vim.in
index 39d7193..a7c857e 100644
--- a/Auxiliary/vim/cmake.vim.in
+++ b/Auxiliary/vim/cmake.vim.in
@@ -13,16 +13,25 @@
 "               https://cmake.org/licensing
 "               This implies that distribution with Vim is allowed
 
-if exists("b:current_syntax")
+if exists('b:current_syntax')
   finish
 endif
-let s:keepcpo= &cpo
-set cpo&vim
+let s:keepcpo= &cpoptions
+set cpoptions&vim
 
-syn region cmakeBracketArgument start="\[\z(=\?\|=[0-9]*\)\[" end="\]\z1\]" contains=cmakeTodo,@Spell
+syn cluster cmakeControl contains=
+      \ cmakeIf,
+      \ cmakeElse,
+      \ cmakeForeach,
+      \ cmakeWhile,
+      \ cmakeBlock,
+      \ cmakeFunction,
+      \ cmakeMacro
 
-syn region cmakeComment start="#" end="$" contains=cmakeTodo,@Spell
-syn region cmakeBracketComment start="\[\z(=*\)\[" end="\]\z1\]" contains=cmakeTodo,@Spell
+syn region cmakeBracketArgument start="\[\z(=*\)\[" end="\]\z1\]" fold contains=cmakeTodo,@Spell
+
+syn region cmakeComment start="#\(\[=*\[\)\@!" end="$" contains=cmakeTodo,@Spell
+syn region cmakeBracketComment start="#\[\z(=*\)\[" end="\]\z1\]" fold contains=cmakeTodo,@Spell
 
 syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained
 syn region cmakeRegistry start="\[" end="]" contained oneline contains=cmakeTodo,cmakeEscaped
@@ -35,7 +44,15 @@
 
 syn region cmakeEnvironment start="$ENV{" end="}" contained oneline contains=cmakeTodo
 
-syn region cmakeArguments start="(" end=")" contains=ALLBUT,cmakeGeneratorExpressions,cmakeCommand,cmakeCommandConditional,cmakeCommandRepeat,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo,@Spell
+syn region cmakeArguments start="(" end=")" contains=ALLBUT,@cmakeControl,cmakeGeneratorExpressions,cmakeCommand,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo,@Spell fold
+syn region cmakeIf matchgroup=cmakeKeyword start=/^\s*\<if\>/ end=/^\s*\<endif\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn match cmakeElse /^\s*\<else\(if\)\?\>/ contained contains=NONE
+
+syn region cmakeForeach matchgroup=cmakeKeyword start=/^\s*\<foreach\>/ end=/^\s*\<endforeach\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn region cmakeWhile matchgroup=cmakeKeyword start=/^\s*\<while\>/ end=/^\s*\<endwhile\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn region cmakeFunction matchgroup=cmakeKeyword start=/^\s*\<function\>/ end=/^\s*\<endfunction\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn region cmakeBlock matchgroup=cmakeKeyword start=/^\s*\<block\>/ end=/^\s*\<endblock\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn region cmakeMacro matchgroup=cmakeKeyword start=/^\s*\<macro\>/ end=/^\s*\<endmacro\>/ transparent fold contains=@cmakeControl,cmakeArguments
 
 syn case match
 
@@ -59,14 +76,6 @@
 @COMMAND_LIST@
             \ nextgroup=cmakeArguments
 
-syn keyword cmakeCommandConditional
-@CONDITIONALS@
-            \ nextgroup=cmakeArguments
-
-syn keyword cmakeCommandRepeat
-@LOOPS@
-            \ nextgroup=cmakeArguments
-
 syn keyword cmakeCommandDeprecated
 @DEPRECATED@
             \ nextgroup=cmakeArguments
@@ -80,14 +89,14 @@
 hi def link cmakeBracketArgument String
 hi def link cmakeBracketComment Comment
 hi def link cmakeCommand Function
-hi def link cmakeCommandConditional Conditional
 hi def link cmakeCommandDeprecated WarningMsg
-hi def link cmakeCommandRepeat Repeat
 hi def link cmakeComment Comment
+hi def link cmakeElse Conditional
 hi def link cmakeEnvironment Special
 hi def link cmakeEscaped Special
 hi def link cmakeGeneratorExpression WarningMsg
 hi def link cmakeGeneratorExpressions Constant
+hi def link cmakeKeyword Conditional
 hi def link cmakeModule Include
 hi def link cmakeProperty Constant
 hi def link cmakeRegistry Underlined
@@ -122,9 +131,9 @@
 hi def link cmakeKWwrite_basic_package_version_file ModeMsg
 hi def link cmakeKWconfigure_package_config_file_constants Constant
 
-let b:current_syntax = "cmake"
+let b:current_syntax = 'cmake'
 
-let &cpo = s:keepcpo
+let &cpoptions = s:keepcpo
 unlet s:keepcpo
 
 " vim: set nowrap:
diff --git a/Auxiliary/vim/extract-upper-case.pl b/Auxiliary/vim/extract-upper-case.pl
index 7f40b74..ed821b5 100755
--- a/Auxiliary/vim/extract-upper-case.pl
+++ b/Auxiliary/vim/extract-upper-case.pl
@@ -24,7 +24,7 @@
 
 # control-statements
 my %conditional = map { $_ => 1 } qw(if else elseif endif);
-my %loop = map { $_ => 1 } qw(foreach while endforeach endwhile);
+my %loopetc = map { $_ => 1 } qw(block foreach function macro while endblock endfunction endforeach endmacro endwhile);
 
 # decrecated
 my %deprecated = map { $_ => 1 } qw(build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory output_required_files remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file);
@@ -141,7 +141,7 @@
 		if ($1 eq "COMMAND_LIST") {
 			# do not include "special" commands in this list
 			my @tmp = grep { ! exists $conditional{$_} and
-			                 ! exists $loop{$_} and
+			                 ! exists $loopetc{$_} and
 			                 ! exists $deprecated{$_} } @commands;
 			print_list(\*OUT, @tmp);
 		} elsif ($1 eq "VARIABLE_LIST") {
@@ -150,10 +150,6 @@
 			print_list(\*OUT, @modules);
 		} elsif ($1 eq "GENERATOR_EXPRESSIONS") {
 			print_list(\*OUT, @generator_expr);
-		} elsif ($1 eq "CONDITIONALS") {
-			print_list(\*OUT, keys %conditional);
-		} elsif ($1 eq "LOOPS") {
-			print_list(\*OUT, keys %loop);
 		} elsif ($1 eq "DEPRECATED") {
 			print_list(\*OUT, keys %deprecated);
 		} elsif ($1 eq "PROPERTIES") {
diff --git a/Auxiliary/vim/indent/cmake.vim b/Auxiliary/vim/indent/cmake.vim
index 28ecf84..fe30643 100644
--- a/Auxiliary/vim/indent/cmake.vim
+++ b/Auxiliary/vim/indent/cmake.vim
@@ -9,7 +9,7 @@
 "               https://cmake.org/licensing
 "               This implies that distribution with Vim is allowed
 
-if exists("b:did_indent")
+if exists('b:did_indent')
   finish
 endif
 let b:did_indent = 1
@@ -20,11 +20,11 @@
 let b:undo_indent = "setl inde< indk<"
 
 " Only define the function once.
-if exists("*CMakeGetIndent")
+if exists('*CMakeGetIndent')
   finish
 endif
-let s:keepcpo= &cpo
-set cpo&vim
+let s:keepcpo= &cpoptions
+set cpoptions&vim
 
 fun! CMakeGetIndent(lnum)
   let this_line = getline(a:lnum)
@@ -95,5 +95,5 @@
   return ind
 endfun
 
-let &cpo = s:keepcpo
+let &cpoptions = s:keepcpo
 unlet s:keepcpo
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 64e18e8..ad560c9 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -1,13 +1,13 @@
 " Vim syntax file
 " Program:      CMake - Cross-Platform Makefile Generator
-" Version:      cmake version 3.27.20230713-gdc88dd5
+" Version:      cmake version 4.1.20250715-g2c3f83a
 " Language:     CMake
 " Author:       Andy Cedilnik <andy.cedilnik@kitware.com>,
 "               Nicholas Hutchinson <nshutchinson@gmail.com>,
 "               Patrick Boettcher <patrick.boettcher@posteo.de>
 " Maintainer:   Dimitri Merejkowsky <d.merej@gmail.com>
 " Former Maintainer: Karthik Krishnan <karthik.krishnan@kitware.com>
-" Last Change:  2023 Jul 13
+" Last Change:  2025 Jul 15
 "
 " License:      The CMake license applies to this file. See
 "               https://cmake.org/licensing
@@ -19,10 +19,19 @@
 let s:keepcpo= &cpo
 set cpo&vim
 
-syn region cmakeBracketArgument start="\[\z(=*\)\[" end="\]\z1\]" contains=cmakeTodo,@Spell
+syn cluster cmakeControl contains=
+      \ cmakeIf,
+      \ cmakeElse,
+      \ cmakeForeach,
+      \ cmakeWhile,
+      \ cmakeBlock,
+      \ cmakeFunction,
+      \ cmakeMacro
+
+syn region cmakeBracketArgument start="\[\z(=*\)\[" end="\]\z1\]" fold contains=cmakeTodo,@Spell
 
 syn region cmakeComment start="#\(\[=*\[\)\@!" end="$" contains=cmakeTodo,@Spell
-syn region cmakeBracketComment start="#\[\z(=*\)\[" end="\]\z1\]" contains=cmakeTodo,@Spell
+syn region cmakeBracketComment start="#\[\z(=*\)\[" end="\]\z1\]" fold contains=cmakeTodo,@Spell
 
 syn match cmakeEscaped /\(\\\\\|\\"\|\\n\|\\t\)/ contained
 syn region cmakeRegistry start="\[" end="]" contained oneline contains=cmakeTodo,cmakeEscaped
@@ -35,7 +44,15 @@
 
 syn region cmakeEnvironment start="$ENV{" end="}" contained oneline contains=cmakeTodo
 
-syn region cmakeArguments start="(" end=")" contains=ALLBUT,cmakeGeneratorExpressions,cmakeCommand,cmakeCommandConditional,cmakeCommandRepeat,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo,@Spell
+syn region cmakeArguments start="(" end=")" contains=ALLBUT,@cmakeControl,cmakeGeneratorExpressions,cmakeCommand,cmakeCommandDeprecated,cmakeCommandManuallyAdded,cmakeArguments,cmakeTodo,@Spell fold
+syn region cmakeIf matchgroup=cmakeKeyword start=/^\s*\<if\>/ end=/^\s*\<endif\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn match cmakeElse /^\s*\<else\(if\)\?\>/ contained contains=NONE
+
+syn region cmakeForeach matchgroup=cmakeKeyword start=/^\s*\<foreach\>/ end=/^\s*\<endforeach\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn region cmakeWhile matchgroup=cmakeKeyword start=/^\s*\<while\>/ end=/^\s*\<endwhile\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn region cmakeFunction matchgroup=cmakeKeyword start=/^\s*\<function\>/ end=/^\s*\<endfunction\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn region cmakeBlock matchgroup=cmakeKeyword start=/^\s*\<block\>/ end=/^\s*\<endblock\>/ transparent fold contains=@cmakeControl,cmakeArguments
+syn region cmakeMacro matchgroup=cmakeKeyword start=/^\s*\<macro\>/ end=/^\s*\<endmacro\>/ transparent fold contains=@cmakeControl,cmakeArguments
 
 syn case match
 
@@ -45,6 +62,7 @@
             \ ADDITIONAL_MAKE_CLEAN_FILES
             \ ADVANCED
             \ AIX_EXPORT_ALL_SYMBOLS
+            \ AIX_SHARED_LIBRARY_ARCHIVE
             \ ALIASED_TARGET
             \ ALIAS_GLOBAL
             \ ALLOW_DUPLICATE_CUSTOM_TARGETS
@@ -69,20 +87,20 @@
             \ ARCHIVE_OUTPUT_NAME
             \ ATTACHED_FILES
             \ ATTACHED_FILES_ON_FAIL
+            \ AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
             \ AUTOGEN_BUILD_DIR
             \ AUTOGEN_COMMAND_LINE_LENGTH_MAX
             \ AUTOGEN_ORIGIN_DEPENDS
             \ AUTOGEN_PARALLEL
             \ AUTOGEN_SOURCE_GROUP
-            \ AUTOGEN_USE_SYSTEM_INCLUDE
             \ AUTOGEN_TARGETS_FOLDER
             \ AUTOGEN_TARGET_DEPENDS
             \ AUTOGEN_USE_SYSTEM_INCLUDE
-            \ AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
             \ AUTOMOC
             \ AUTOMOC_COMPILER_PREDEFINES
             \ AUTOMOC_DEPEND_FILTERS
             \ AUTOMOC_EXECUTABLE
+            \ AUTOMOC_INCLUDE_DIRECTORIES
             \ AUTOMOC_MACRO_NAMES
             \ AUTOMOC_MOC_OPTIONS
             \ AUTOMOC_PATH_PREFIX
@@ -111,6 +129,7 @@
             \ CMAKE_CUDA_KNOWN_FEATURES
             \ CMAKE_CXX_KNOWN_FEATURES
             \ CMAKE_C_KNOWN_FEATURES
+            \ CMAKE_HIP_KNOWN_FEATURES
             \ CMAKE_ROLE
             \ COMMON_LANGUAGE_RUNTIME
             \ COMPATIBLE_INTERFACE_BOOL
@@ -147,15 +166,16 @@
             \ CXX_MODULE_DIRS
             \ CXX_MODULE_SET
             \ CXX_MODULE_SETS
+            \ CXX_MODULE_STD
             \ CXX_SCAN_FOR_MODULES
             \ CXX_STANDARD
             \ CXX_STANDARD_REQUIRED
             \ C_EXTENSIONS
             \ C_STANDARD
             \ C_STANDARD_REQUIRED
+            \ DEBUGGER_WORKING_DIRECTORY
             \ DEBUG_CONFIGURATIONS
             \ DEBUG_POSTFIX
-            \ DEBUGGER_WORKING_DIRECTORY
             \ DEFINE_SYMBOL
             \ DEFINITIONS
             \ DEPENDS
@@ -178,7 +198,9 @@
             \ ENVIRONMENT_MODIFICATION
             \ EXCLUDE_FROM_ALL
             \ EXCLUDE_FROM_DEFAULT_BUILD
+            \ EXPORT_BUILD_DATABASE
             \ EXPORT_COMPILE_COMMANDS
+            \ EXPORT_FIND_PACKAGE_NAME
             \ EXPORT_NAME
             \ EXPORT_NO_SYSTEM
             \ EXPORT_PROPERTIES
@@ -195,11 +217,13 @@
             \ FOLDER
             \ FRAMEWORK
             \ FRAMEWORK_VERSION
+            \ Fortran_BUILDING_INSTRINSIC_MODULES
             \ Fortran_BUILDING_INTRINSIC_MODULES
             \ Fortran_FORMAT
             \ Fortran_MODULE_DIRECTORY
             \ Fortran_PREPROCESS
             \ GENERATED
+            \ GENERATED_RESOURCE_SPEC_FILE
             \ GENERATOR_FILE_NAME
             \ GENERATOR_IS_MULTI_CONFIG
             \ GHS_INTEGRITY_APP
@@ -221,6 +245,11 @@
             \ IMPORTED
             \ IMPORTED_COMMON_LANGUAGE_RUNTIME
             \ IMPORTED_CONFIGURATIONS
+            \ IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS
+            \ IMPORTED_CXX_MODULES_COMPILE_FEATURES
+            \ IMPORTED_CXX_MODULES_COMPILE_OPTIONS
+            \ IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES
+            \ IMPORTED_CXX_MODULES_LINK_LIBRARIES
             \ IMPORTED_GLOBAL
             \ IMPORTED_IMPLIB
             \ IMPORTED_LIBNAME
@@ -239,12 +268,12 @@
             \ INCLUDE_DIRECTORIES
             \ INCLUDE_REGULAR_EXPRESSION
             \ INSTALL_NAME_DIR
+            \ INSTALL_PARALLEL
             \ INSTALL_REMOVE_ENVIRONMENT_RPATH
             \ INSTALL_RPATH
             \ INSTALL_RPATH_USE_LINK_PATH
             \ INTERFACE_AUTOMOC_MACRO_NAMES
             \ INTERFACE_AUTOUIC_OPTIONS
-            \ INTERFACE_AUTOMOC_MACRO_NAMES
             \ INTERFACE_COMPILE_DEFINITIONS
             \ INTERFACE_COMPILE_FEATURES
             \ INTERFACE_COMPILE_OPTIONS
@@ -278,6 +307,7 @@
             \ LIBRARY_OUTPUT_DIRECTORY
             \ LIBRARY_OUTPUT_NAME
             \ LINKER_LANGUAGE
+            \ LINKER_TYPE
             \ LINK_DEPENDS
             \ LINK_DEPENDS_NO_SHARED
             \ LINK_DIRECTORIES
@@ -286,10 +316,12 @@
             \ LINK_INTERFACE_MULTIPLICITY
             \ LINK_LIBRARIES
             \ LINK_LIBRARIES_ONLY_TARGETS
+            \ LINK_LIBRARIES_STRATEGY
             \ LINK_LIBRARY_OVERRIDE
             \ LINK_OPTIONS
             \ LINK_SEARCH_END_STATIC
             \ LINK_SEARCH_START_STATIC
+            \ LINK_WARNING_AS_ERROR
             \ LINK_WHAT_YOU_USE
             \ LISTFILE_STACK
             \ LOCATION
@@ -340,6 +372,7 @@
             \ PROCESSORS
             \ PROCESSOR_AFFINITY
             \ PROJECT_LABEL
+            \ PROPAGATE_TOP_LEVEL_INCLUDES_TO_TRY_COMPILE
             \ PUBLIC_HEADER
             \ REPORT_UNDEFINED_PROPERTIES
             \ REQUIRED_FILES
@@ -366,6 +399,7 @@
             \ SOURCES
             \ SOURCE_DIR
             \ SOVERSION
+            \ SPDX_LICENSE
             \ STATIC_LIBRARY_FLAGS
             \ STATIC_LIBRARY_OPTIONS
             \ STRINGS
@@ -373,28 +407,32 @@
             \ SUFFIX
             \ SYMBOLIC
             \ SYSTEM
+            \ Swift_COMPILATION_MODE
             \ Swift_DEPENDENCIES_FILE
             \ Swift_DIAGNOSTICS_FILE
             \ Swift_LANGUAGE_VERSION
             \ Swift_MODULE_DIRECTORY
             \ Swift_MODULE_NAME
-            \ Swift_COMPILATION_MODE
             \ TARGET_ARCHIVES_MAY_BE_SHARED_LIBS
             \ TARGET_MESSAGES
             \ TARGET_SUPPORTS_SHARED_LIBS
             \ TESTS
             \ TEST_INCLUDE_FILE
             \ TEST_INCLUDE_FILES
+            \ TEST_LAUNCHER
             \ TIMEOUT
             \ TIMEOUT_AFTER_MATCH
             \ TIMEOUT_SIGNAL_GRACE_PERIOD
             \ TIMEOUT_SIGNAL_NAME
+            \ TRANSITIVE_COMPILE_PROPERTIES
+            \ TRANSITIVE_LINK_PROPERTIES
             \ TYPE
             \ UNITY_BUILD
             \ UNITY_BUILD_BATCH_SIZE
             \ UNITY_BUILD_CODE_AFTER_INCLUDE
             \ UNITY_BUILD_CODE_BEFORE_INCLUDE
             \ UNITY_BUILD_MODE
+            \ UNITY_BUILD_RELOCATABLE
             \ UNITY_BUILD_UNIQUE_ID
             \ UNITY_GROUP
             \ USE_FOLDERS
@@ -405,6 +443,7 @@
             \ VISIBILITY_INLINES_HIDDEN
             \ VS_CONFIGURATION_TYPE
             \ VS_COPY_TO_OUT_DIR
+            \ VS_CUSTOM_COMMAND_DISABLE_PARALLEL_BUILD
             \ VS_DEBUGGER_COMMAND
             \ VS_DEBUGGER_COMMAND_ARGUMENTS
             \ VS_DEBUGGER_ENVIRONMENT
@@ -418,6 +457,7 @@
             \ VS_DOTNET_STARTUP_OBJECT
             \ VS_DOTNET_TARGET_FRAMEWORK_VERSION
             \ VS_DPI_AWARE
+            \ VS_FILTER_PROPS
             \ VS_FRAMEWORK_REFERENCES
             \ VS_GLOBAL_KEYWORD
             \ VS_GLOBAL_PROJECT_TYPES
@@ -450,10 +490,11 @@
             \ VS_SHADER_TYPE
             \ VS_SHADER_VARIABLE_NAME
             \ VS_SOLUTION_DEPLOY
+            \ VS_SOLUTION_ITEMS
             \ VS_STARTUP_PROJECT
             \ VS_TOOL_OVERRIDE
             \ VS_USER_PROPS
-            \ VS_FILTER_PROPS
+            \ VS_USE_DEBUG_LIBRARIES
             \ VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
             \ VS_WINRT_COMPONENT
             \ VS_WINRT_EXTENSIONS
@@ -479,45 +520,46 @@
             \ XCODE_SCHEME_ARGUMENTS
             \ XCODE_SCHEME_DEBUG_AS_ROOT
             \ XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
-            \ XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE
             \ XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
             \ XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
             \ XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
             \ XCODE_SCHEME_ENABLE_GPU_API_VALIDATION
+            \ XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE
             \ XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION
             \ XCODE_SCHEME_ENVIRONMENT
             \ XCODE_SCHEME_EXECUTABLE
             \ XCODE_SCHEME_GUARD_MALLOC
+            \ XCODE_SCHEME_LAUNCH_CONFIGURATION
             \ XCODE_SCHEME_LAUNCH_MODE
             \ XCODE_SCHEME_LLDB_INIT_FILE
             \ XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
             \ XCODE_SCHEME_MALLOC_GUARD_EDGES
             \ XCODE_SCHEME_MALLOC_SCRIBBLE
             \ XCODE_SCHEME_MALLOC_STACK
+            \ XCODE_SCHEME_TEST_CONFIGURATION
             \ XCODE_SCHEME_THREAD_SANITIZER
             \ XCODE_SCHEME_THREAD_SANITIZER_STOP
             \ XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
             \ XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
-            \ XCODE_SCHEME_ENABLE_GPU_API_VALIDATION
-            \ XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION
-            \ XCODE_SCHEME_LAUNCH_CONFIGURATION
-            \ XCODE_SCHEME_TEST_CONFIGURATION
             \ XCODE_SCHEME_WORKING_DIRECTORY
             \ XCODE_SCHEME_ZOMBIE_OBJECTS
             \ XCODE_XCCONFIG
             \ XCTEST
 
 syn keyword cmakeVariable contained
+            \ AIX
             \ ANDROID
             \ APPLE
             \ BORLAND
             \ BSD
             \ BUILD_SHARED_LIBS
+            \ BUILD_TESTING
             \ CACHE
             \ CMAKE_ABSOLUTE_DESTINATION_FILES
             \ CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY
             \ CMAKE_ADSP_ROOT
             \ CMAKE_AIX_EXPORT_ALL_SYMBOLS
+            \ CMAKE_AIX_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
             \ CMAKE_ANDROID_API
             \ CMAKE_ANDROID_API_MIN
@@ -556,9 +598,12 @@
             \ CMAKE_ASM_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_ASM_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_ASM_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_ASM_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_ASM_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_ASM_ARCHIVE_APPEND
             \ CMAKE_ASM_ARCHIVE_CREATE
             \ CMAKE_ASM_ARCHIVE_FINISH
+            \ CMAKE_ASM_ATTRIBUTES
             \ CMAKE_ASM_BYTE_ORDER
             \ CMAKE_ASM_CLANG_TIDY
             \ CMAKE_ASM_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -570,6 +615,10 @@
             \ CMAKE_ASM_COMPILER_FRONTEND_VARIANT
             \ CMAKE_ASM_COMPILER_ID
             \ CMAKE_ASM_COMPILER_LAUNCHER
+            \ CMAKE_ASM_COMPILER_LINKER
+            \ CMAKE_ASM_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_ASM_COMPILER_LINKER_ID
+            \ CMAKE_ASM_COMPILER_LINKER_VERSION
             \ CMAKE_ASM_COMPILER_LOADED
             \ CMAKE_ASM_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_ASM_COMPILER_RANLIB
@@ -580,8 +629,10 @@
             \ CMAKE_ASM_CPPCHECK
             \ CMAKE_ASM_CPPLINT
             \ CMAKE_ASM_CREATE_SHARED_LIBRARY
+            \ CMAKE_ASM_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_ASM_CREATE_SHARED_MODULE
             \ CMAKE_ASM_CREATE_STATIC_LIBRARY
+            \ CMAKE_ASM_DEVICE_LINK_MODE
             \ CMAKE_ASM_EXTENSIONS
             \ CMAKE_ASM_EXTENSIONS_DEFAULT
             \ CMAKE_ASM_FLAGS
@@ -594,6 +645,10 @@
             \ CMAKE_ASM_FLAGS_RELEASE_INIT
             \ CMAKE_ASM_FLAGS_RELWITHDEBINFO
             \ CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_ASM_HOST_COMPILER
+            \ CMAKE_ASM_HOST_COMPILER_ID
+            \ CMAKE_ASM_HOST_COMPILER_VERSION
+            \ CMAKE_ASM_ICSTAT
             \ CMAKE_ASM_IGNORE_EXTENSIONS
             \ CMAKE_ASM_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_ASM_IMPLICIT_LINK_DIRECTORIES
@@ -607,18 +662,23 @@
             \ CMAKE_ASM_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_ASM_LINKER_WRAPPER_FLAG
             \ CMAKE_ASM_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_ASM_LINK_DEF_FILE_FLAG
             \ CMAKE_ASM_LINK_EXECUTABLE
             \ CMAKE_ASM_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_ASM_LINK_LIBRARY_FLAG
             \ CMAKE_ASM_LINK_LIBRARY_SUFFIX
+            \ CMAKE_ASM_LINK_MODE
             \ CMAKE_ASM_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_ASM_MASM
             \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_ASM_MASM_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_ASM_MASM_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_ASM_MASM_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_ASM_MASM_ARCHIVE_APPEND
             \ CMAKE_ASM_MASM_ARCHIVE_CREATE
             \ CMAKE_ASM_MASM_ARCHIVE_FINISH
+            \ CMAKE_ASM_MASM_ATTRIBUTES
             \ CMAKE_ASM_MASM_BYTE_ORDER
             \ CMAKE_ASM_MASM_CLANG_TIDY
             \ CMAKE_ASM_MASM_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -630,6 +690,10 @@
             \ CMAKE_ASM_MASM_COMPILER_FRONTEND_VARIANT
             \ CMAKE_ASM_MASM_COMPILER_ID
             \ CMAKE_ASM_MASM_COMPILER_LAUNCHER
+            \ CMAKE_ASM_MASM_COMPILER_LINKER
+            \ CMAKE_ASM_MASM_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_ASM_MASM_COMPILER_LINKER_ID
+            \ CMAKE_ASM_MASM_COMPILER_LINKER_VERSION
             \ CMAKE_ASM_MASM_COMPILER_LOADED
             \ CMAKE_ASM_MASM_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_ASM_MASM_COMPILER_RANLIB
@@ -640,8 +704,10 @@
             \ CMAKE_ASM_MASM_CPPCHECK
             \ CMAKE_ASM_MASM_CPPLINT
             \ CMAKE_ASM_MASM_CREATE_SHARED_LIBRARY
+            \ CMAKE_ASM_MASM_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_ASM_MASM_CREATE_SHARED_MODULE
             \ CMAKE_ASM_MASM_CREATE_STATIC_LIBRARY
+            \ CMAKE_ASM_MASM_DEVICE_LINK_MODE
             \ CMAKE_ASM_MASM_EXTENSIONS
             \ CMAKE_ASM_MASM_EXTENSIONS_DEFAULT
             \ CMAKE_ASM_MASM_FLAGS
@@ -654,6 +720,10 @@
             \ CMAKE_ASM_MASM_FLAGS_RELEASE_INIT
             \ CMAKE_ASM_MASM_FLAGS_RELWITHDEBINFO
             \ CMAKE_ASM_MASM_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_ASM_MASM_HOST_COMPILER
+            \ CMAKE_ASM_MASM_HOST_COMPILER_ID
+            \ CMAKE_ASM_MASM_HOST_COMPILER_VERSION
+            \ CMAKE_ASM_MASM_ICSTAT
             \ CMAKE_ASM_MASM_IGNORE_EXTENSIONS
             \ CMAKE_ASM_MASM_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_ASM_MASM_IMPLICIT_LINK_DIRECTORIES
@@ -667,10 +737,12 @@
             \ CMAKE_ASM_MASM_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_ASM_MASM_LINKER_WRAPPER_FLAG
             \ CMAKE_ASM_MASM_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_ASM_MASM_LINK_DEF_FILE_FLAG
             \ CMAKE_ASM_MASM_LINK_EXECUTABLE
             \ CMAKE_ASM_MASM_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_ASM_MASM_LINK_LIBRARY_FLAG
             \ CMAKE_ASM_MASM_LINK_LIBRARY_SUFFIX
+            \ CMAKE_ASM_MASM_LINK_MODE
             \ CMAKE_ASM_MASM_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_ASM_MASM_OUTPUT_EXTENSION
             \ CMAKE_ASM_MASM_PLATFORM_ID
@@ -681,17 +753,23 @@
             \ CMAKE_ASM_MASM_STANDARD
             \ CMAKE_ASM_MASM_STANDARD_DEFAULT
             \ CMAKE_ASM_MASM_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_ASM_MASM_STANDARD_LATEST
             \ CMAKE_ASM_MASM_STANDARD_LIBRARIES
+            \ CMAKE_ASM_MASM_STANDARD_LINK_DIRECTORIES
             \ CMAKE_ASM_MASM_STANDARD_REQUIRED
             \ CMAKE_ASM_MASM_SUPPORTED
+            \ CMAKE_ASM_MASM_USING_LINKER_MODE
             \ CMAKE_ASM_MASM_VISIBILITY_PRESET
             \ CMAKE_ASM_NASM
             \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_ASM_NASM_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_ASM_NASM_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_ASM_NASM_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_ASM_NASM_ARCHIVE_APPEND
             \ CMAKE_ASM_NASM_ARCHIVE_CREATE
             \ CMAKE_ASM_NASM_ARCHIVE_FINISH
+            \ CMAKE_ASM_NASM_ATTRIBUTES
             \ CMAKE_ASM_NASM_BYTE_ORDER
             \ CMAKE_ASM_NASM_CLANG_TIDY
             \ CMAKE_ASM_NASM_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -703,6 +781,10 @@
             \ CMAKE_ASM_NASM_COMPILER_FRONTEND_VARIANT
             \ CMAKE_ASM_NASM_COMPILER_ID
             \ CMAKE_ASM_NASM_COMPILER_LAUNCHER
+            \ CMAKE_ASM_NASM_COMPILER_LINKER
+            \ CMAKE_ASM_NASM_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_ASM_NASM_COMPILER_LINKER_ID
+            \ CMAKE_ASM_NASM_COMPILER_LINKER_VERSION
             \ CMAKE_ASM_NASM_COMPILER_LOADED
             \ CMAKE_ASM_NASM_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_ASM_NASM_COMPILER_RANLIB
@@ -713,8 +795,10 @@
             \ CMAKE_ASM_NASM_CPPCHECK
             \ CMAKE_ASM_NASM_CPPLINT
             \ CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY
+            \ CMAKE_ASM_NASM_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_ASM_NASM_CREATE_SHARED_MODULE
             \ CMAKE_ASM_NASM_CREATE_STATIC_LIBRARY
+            \ CMAKE_ASM_NASM_DEVICE_LINK_MODE
             \ CMAKE_ASM_NASM_EXTENSIONS
             \ CMAKE_ASM_NASM_EXTENSIONS_DEFAULT
             \ CMAKE_ASM_NASM_FLAGS
@@ -727,6 +811,10 @@
             \ CMAKE_ASM_NASM_FLAGS_RELEASE_INIT
             \ CMAKE_ASM_NASM_FLAGS_RELWITHDEBINFO
             \ CMAKE_ASM_NASM_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_ASM_NASM_HOST_COMPILER
+            \ CMAKE_ASM_NASM_HOST_COMPILER_ID
+            \ CMAKE_ASM_NASM_HOST_COMPILER_VERSION
+            \ CMAKE_ASM_NASM_ICSTAT
             \ CMAKE_ASM_NASM_IGNORE_EXTENSIONS
             \ CMAKE_ASM_NASM_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_ASM_NASM_IMPLICIT_LINK_DIRECTORIES
@@ -740,10 +828,12 @@
             \ CMAKE_ASM_NASM_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_ASM_NASM_LINKER_WRAPPER_FLAG
             \ CMAKE_ASM_NASM_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_ASM_NASM_LINK_DEF_FILE_FLAG
             \ CMAKE_ASM_NASM_LINK_EXECUTABLE
             \ CMAKE_ASM_NASM_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_ASM_NASM_LINK_LIBRARY_FLAG
             \ CMAKE_ASM_NASM_LINK_LIBRARY_SUFFIX
+            \ CMAKE_ASM_NASM_LINK_MODE
             \ CMAKE_ASM_NASM_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_ASM_NASM_OUTPUT_EXTENSION
             \ CMAKE_ASM_NASM_PLATFORM_ID
@@ -754,9 +844,12 @@
             \ CMAKE_ASM_NASM_STANDARD
             \ CMAKE_ASM_NASM_STANDARD_DEFAULT
             \ CMAKE_ASM_NASM_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_ASM_NASM_STANDARD_LATEST
             \ CMAKE_ASM_NASM_STANDARD_LIBRARIES
+            \ CMAKE_ASM_NASM_STANDARD_LINK_DIRECTORIES
             \ CMAKE_ASM_NASM_STANDARD_REQUIRED
             \ CMAKE_ASM_NASM_SUPPORTED
+            \ CMAKE_ASM_NASM_USING_LINKER_MODE
             \ CMAKE_ASM_NASM_VISIBILITY_PRESET
             \ CMAKE_ASM_OUTPUT_EXTENSION
             \ CMAKE_ASM_PLATFORM_ID
@@ -767,9 +860,12 @@
             \ CMAKE_ASM_STANDARD
             \ CMAKE_ASM_STANDARD_DEFAULT
             \ CMAKE_ASM_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_ASM_STANDARD_LATEST
             \ CMAKE_ASM_STANDARD_LIBRARIES
+            \ CMAKE_ASM_STANDARD_LINK_DIRECTORIES
             \ CMAKE_ASM_STANDARD_REQUIRED
             \ CMAKE_ASM_SUPPORTED
+            \ CMAKE_ASM_USING_LINKER_MODE
             \ CMAKE_ASM_VISIBILITY_PRESET
             \ CMAKE_AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
             \ CMAKE_AUTOGEN_COMMAND_LINE_LENGTH_MAX
@@ -781,20 +877,18 @@
             \ CMAKE_AUTOMOC_COMPILER_PREDEFINES
             \ CMAKE_AUTOMOC_DEPEND_FILTERS
             \ CMAKE_AUTOMOC_EXECUTABLE
+            \ CMAKE_AUTOMOC_INCLUDE_DIRECTORIES
             \ CMAKE_AUTOMOC_MACRO_NAMES
             \ CMAKE_AUTOMOC_MOC_OPTIONS
             \ CMAKE_AUTOMOC_PATH_PREFIX
             \ CMAKE_AUTOMOC_RELAXED_MODE
-            \ CMAKE_AUTOMOC_EXECUTABLE
             \ CMAKE_AUTORCC
             \ CMAKE_AUTORCC_EXECUTABLE
             \ CMAKE_AUTORCC_OPTIONS
-            \ CMAKE_AUTORCC_EXECUTABLE
             \ CMAKE_AUTOUIC
             \ CMAKE_AUTOUIC_EXECUTABLE
             \ CMAKE_AUTOUIC_OPTIONS
             \ CMAKE_AUTOUIC_SEARCH_PATHS
-            \ CMAKE_AUTOUIC_EXECUTABLE
             \ CMAKE_BACKWARDS_COMPATIBILITY
             \ CMAKE_BINARY_DIR
             \ CMAKE_BUILD_RPATH
@@ -832,9 +926,12 @@
             \ CMAKE_CSharp_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_CSharp_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_CSharp_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_CSharp_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_CSharp_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_CSharp_ARCHIVE_APPEND
             \ CMAKE_CSharp_ARCHIVE_CREATE
             \ CMAKE_CSharp_ARCHIVE_FINISH
+            \ CMAKE_CSharp_ATTRIBUTES
             \ CMAKE_CSharp_BYTE_ORDER
             \ CMAKE_CSharp_CLANG_TIDY
             \ CMAKE_CSharp_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -846,6 +943,10 @@
             \ CMAKE_CSharp_COMPILER_FRONTEND_VARIANT
             \ CMAKE_CSharp_COMPILER_ID
             \ CMAKE_CSharp_COMPILER_LAUNCHER
+            \ CMAKE_CSharp_COMPILER_LINKER
+            \ CMAKE_CSharp_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_CSharp_COMPILER_LINKER_ID
+            \ CMAKE_CSharp_COMPILER_LINKER_VERSION
             \ CMAKE_CSharp_COMPILER_LOADED
             \ CMAKE_CSharp_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_CSharp_COMPILER_RANLIB
@@ -856,8 +957,10 @@
             \ CMAKE_CSharp_CPPCHECK
             \ CMAKE_CSharp_CPPLINT
             \ CMAKE_CSharp_CREATE_SHARED_LIBRARY
+            \ CMAKE_CSharp_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_CSharp_CREATE_SHARED_MODULE
             \ CMAKE_CSharp_CREATE_STATIC_LIBRARY
+            \ CMAKE_CSharp_DEVICE_LINK_MODE
             \ CMAKE_CSharp_EXTENSIONS
             \ CMAKE_CSharp_EXTENSIONS_DEFAULT
             \ CMAKE_CSharp_FLAGS
@@ -870,6 +973,10 @@
             \ CMAKE_CSharp_FLAGS_RELEASE_INIT
             \ CMAKE_CSharp_FLAGS_RELWITHDEBINFO
             \ CMAKE_CSharp_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_CSharp_HOST_COMPILER
+            \ CMAKE_CSharp_HOST_COMPILER_ID
+            \ CMAKE_CSharp_HOST_COMPILER_VERSION
+            \ CMAKE_CSharp_ICSTAT
             \ CMAKE_CSharp_IGNORE_EXTENSIONS
             \ CMAKE_CSharp_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_CSharp_IMPLICIT_LINK_DIRECTORIES
@@ -883,10 +990,12 @@
             \ CMAKE_CSharp_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_CSharp_LINKER_WRAPPER_FLAG
             \ CMAKE_CSharp_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_CSharp_LINK_DEF_FILE_FLAG
             \ CMAKE_CSharp_LINK_EXECUTABLE
             \ CMAKE_CSharp_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_CSharp_LINK_LIBRARY_FLAG
             \ CMAKE_CSharp_LINK_LIBRARY_SUFFIX
+            \ CMAKE_CSharp_LINK_MODE
             \ CMAKE_CSharp_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_CSharp_OUTPUT_EXTENSION
             \ CMAKE_CSharp_PLATFORM_ID
@@ -897,9 +1006,12 @@
             \ CMAKE_CSharp_STANDARD
             \ CMAKE_CSharp_STANDARD_DEFAULT
             \ CMAKE_CSharp_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_CSharp_STANDARD_LATEST
             \ CMAKE_CSharp_STANDARD_LIBRARIES
+            \ CMAKE_CSharp_STANDARD_LINK_DIRECTORIES
             \ CMAKE_CSharp_STANDARD_REQUIRED
             \ CMAKE_CSharp_SUPPORTED
+            \ CMAKE_CSharp_USING_LINKER_MODE
             \ CMAKE_CSharp_VISIBILITY_PRESET
             \ CMAKE_CTEST_ARGUMENTS
             \ CMAKE_CTEST_COMMAND
@@ -908,9 +1020,12 @@
             \ CMAKE_CUDA_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_CUDA_ANDROID_TOOLCHAIN_SUFFIX
             \ CMAKE_CUDA_ARCHITECTURES
+            \ CMAKE_CUDA_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_CUDA_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_CUDA_ARCHIVE_APPEND
             \ CMAKE_CUDA_ARCHIVE_CREATE
             \ CMAKE_CUDA_ARCHIVE_FINISH
+            \ CMAKE_CUDA_ATTRIBUTES
             \ CMAKE_CUDA_BYTE_ORDER
             \ CMAKE_CUDA_CLANG_TIDY
             \ CMAKE_CUDA_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -922,6 +1037,10 @@
             \ CMAKE_CUDA_COMPILER_FRONTEND_VARIANT
             \ CMAKE_CUDA_COMPILER_ID
             \ CMAKE_CUDA_COMPILER_LAUNCHER
+            \ CMAKE_CUDA_COMPILER_LINKER
+            \ CMAKE_CUDA_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_CUDA_COMPILER_LINKER_ID
+            \ CMAKE_CUDA_COMPILER_LINKER_VERSION
             \ CMAKE_CUDA_COMPILER_LOADED
             \ CMAKE_CUDA_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_CUDA_COMPILER_RANLIB
@@ -933,8 +1052,10 @@
             \ CMAKE_CUDA_CPPCHECK
             \ CMAKE_CUDA_CPPLINT
             \ CMAKE_CUDA_CREATE_SHARED_LIBRARY
+            \ CMAKE_CUDA_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_CUDA_CREATE_SHARED_MODULE
             \ CMAKE_CUDA_CREATE_STATIC_LIBRARY
+            \ CMAKE_CUDA_DEVICE_LINK_MODE
             \ CMAKE_CUDA_EXTENSIONS
             \ CMAKE_CUDA_EXTENSIONS_DEFAULT
             \ CMAKE_CUDA_FLAGS
@@ -948,6 +1069,9 @@
             \ CMAKE_CUDA_FLAGS_RELWITHDEBINFO
             \ CMAKE_CUDA_FLAGS_RELWITHDEBINFO_INIT
             \ CMAKE_CUDA_HOST_COMPILER
+            \ CMAKE_CUDA_HOST_COMPILER_ID
+            \ CMAKE_CUDA_HOST_COMPILER_VERSION
+            \ CMAKE_CUDA_ICSTAT
             \ CMAKE_CUDA_IGNORE_EXTENSIONS
             \ CMAKE_CUDA_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES
@@ -961,10 +1085,12 @@
             \ CMAKE_CUDA_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_CUDA_LINKER_WRAPPER_FLAG
             \ CMAKE_CUDA_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_CUDA_LINK_DEF_FILE_FLAG
             \ CMAKE_CUDA_LINK_EXECUTABLE
             \ CMAKE_CUDA_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_CUDA_LINK_LIBRARY_FLAG
             \ CMAKE_CUDA_LINK_LIBRARY_SUFFIX
+            \ CMAKE_CUDA_LINK_MODE
             \ CMAKE_CUDA_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_CUDA_OUTPUT_EXTENSION
             \ CMAKE_CUDA_PLATFORM_ID
@@ -978,10 +1104,13 @@
             \ CMAKE_CUDA_STANDARD
             \ CMAKE_CUDA_STANDARD_DEFAULT
             \ CMAKE_CUDA_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_CUDA_STANDARD_LATEST
             \ CMAKE_CUDA_STANDARD_LIBRARIES
+            \ CMAKE_CUDA_STANDARD_LINK_DIRECTORIES
             \ CMAKE_CUDA_STANDARD_REQUIRED
             \ CMAKE_CUDA_SUPPORTED
             \ CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES
+            \ CMAKE_CUDA_USING_LINKER_MODE
             \ CMAKE_CUDA_VISIBILITY_PRESET
             \ CMAKE_CURRENT_BINARY_DIR
             \ CMAKE_CURRENT_FUNCTION
@@ -996,9 +1125,12 @@
             \ CMAKE_CXX_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_CXX_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_CXX_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_CXX_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_CXX_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_CXX_ARCHIVE_APPEND
             \ CMAKE_CXX_ARCHIVE_CREATE
             \ CMAKE_CXX_ARCHIVE_FINISH
+            \ CMAKE_CXX_ATTRIBUTES
             \ CMAKE_CXX_BYTE_ORDER
             \ CMAKE_CXX_CLANG_TIDY
             \ CMAKE_CXX_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -1009,7 +1141,12 @@
             \ CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN
             \ CMAKE_CXX_COMPILER_FRONTEND_VARIANT
             \ CMAKE_CXX_COMPILER_ID
+            \ CMAKE_CXX_COMPILER_IMPORT_STD
             \ CMAKE_CXX_COMPILER_LAUNCHER
+            \ CMAKE_CXX_COMPILER_LINKER
+            \ CMAKE_CXX_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_CXX_COMPILER_LINKER_ID
+            \ CMAKE_CXX_COMPILER_LINKER_VERSION
             \ CMAKE_CXX_COMPILER_LOADED
             \ CMAKE_CXX_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_CXX_COMPILER_RANLIB
@@ -1021,8 +1158,10 @@
             \ CMAKE_CXX_CPPCHECK
             \ CMAKE_CXX_CPPLINT
             \ CMAKE_CXX_CREATE_SHARED_LIBRARY
+            \ CMAKE_CXX_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_CXX_CREATE_SHARED_MODULE
             \ CMAKE_CXX_CREATE_STATIC_LIBRARY
+            \ CMAKE_CXX_DEVICE_LINK_MODE
             \ CMAKE_CXX_EXTENSIONS
             \ CMAKE_CXX_EXTENSIONS_DEFAULT
             \ CMAKE_CXX_FLAGS
@@ -1035,6 +1174,10 @@
             \ CMAKE_CXX_FLAGS_RELEASE_INIT
             \ CMAKE_CXX_FLAGS_RELWITHDEBINFO
             \ CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_CXX_HOST_COMPILER
+            \ CMAKE_CXX_HOST_COMPILER_ID
+            \ CMAKE_CXX_HOST_COMPILER_VERSION
+            \ CMAKE_CXX_ICSTAT
             \ CMAKE_CXX_IGNORE_EXTENSIONS
             \ CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES
@@ -1048,11 +1191,14 @@
             \ CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_CXX_LINKER_WRAPPER_FLAG
             \ CMAKE_CXX_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_CXX_LINK_DEF_FILE_FLAG
             \ CMAKE_CXX_LINK_EXECUTABLE
             \ CMAKE_CXX_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_CXX_LINK_LIBRARY_FLAG
             \ CMAKE_CXX_LINK_LIBRARY_SUFFIX
+            \ CMAKE_CXX_LINK_MODE
             \ CMAKE_CXX_LINK_WHAT_YOU_USE_FLAG
+            \ CMAKE_CXX_MODULE_STD
             \ CMAKE_CXX_OUTPUT_EXTENSION
             \ CMAKE_CXX_PLATFORM_ID
             \ CMAKE_CXX_SCAN_FOR_MODULES
@@ -1063,16 +1209,22 @@
             \ CMAKE_CXX_STANDARD
             \ CMAKE_CXX_STANDARD_DEFAULT
             \ CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_CXX_STANDARD_LATEST
             \ CMAKE_CXX_STANDARD_LIBRARIES
+            \ CMAKE_CXX_STANDARD_LINK_DIRECTORIES
             \ CMAKE_CXX_STANDARD_REQUIRED
             \ CMAKE_CXX_SUPPORTED
+            \ CMAKE_CXX_USING_LINKER_MODE
             \ CMAKE_CXX_VISIBILITY_PRESET
             \ CMAKE_C_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_C_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_C_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_C_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_C_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_C_ARCHIVE_APPEND
             \ CMAKE_C_ARCHIVE_CREATE
             \ CMAKE_C_ARCHIVE_FINISH
+            \ CMAKE_C_ATTRIBUTES
             \ CMAKE_C_BYTE_ORDER
             \ CMAKE_C_CLANG_TIDY
             \ CMAKE_C_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -1084,6 +1236,10 @@
             \ CMAKE_C_COMPILER_FRONTEND_VARIANT
             \ CMAKE_C_COMPILER_ID
             \ CMAKE_C_COMPILER_LAUNCHER
+            \ CMAKE_C_COMPILER_LINKER
+            \ CMAKE_C_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_C_COMPILER_LINKER_ID
+            \ CMAKE_C_COMPILER_LINKER_VERSION
             \ CMAKE_C_COMPILER_LOADED
             \ CMAKE_C_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_C_COMPILER_RANLIB
@@ -1095,8 +1251,10 @@
             \ CMAKE_C_CPPCHECK
             \ CMAKE_C_CPPLINT
             \ CMAKE_C_CREATE_SHARED_LIBRARY
+            \ CMAKE_C_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_C_CREATE_SHARED_MODULE
             \ CMAKE_C_CREATE_STATIC_LIBRARY
+            \ CMAKE_C_DEVICE_LINK_MODE
             \ CMAKE_C_EXTENSIONS
             \ CMAKE_C_EXTENSIONS_DEFAULT
             \ CMAKE_C_FLAGS
@@ -1109,6 +1267,10 @@
             \ CMAKE_C_FLAGS_RELEASE_INIT
             \ CMAKE_C_FLAGS_RELWITHDEBINFO
             \ CMAKE_C_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_C_HOST_COMPILER
+            \ CMAKE_C_HOST_COMPILER_ID
+            \ CMAKE_C_HOST_COMPILER_VERSION
+            \ CMAKE_C_ICSTAT
             \ CMAKE_C_IGNORE_EXTENSIONS
             \ CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_C_IMPLICIT_LINK_DIRECTORIES
@@ -1122,10 +1284,12 @@
             \ CMAKE_C_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_C_LINKER_WRAPPER_FLAG
             \ CMAKE_C_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_C_LINK_DEF_FILE_FLAG
             \ CMAKE_C_LINK_EXECUTABLE
             \ CMAKE_C_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_C_LINK_LIBRARY_FLAG
             \ CMAKE_C_LINK_LIBRARY_SUFFIX
+            \ CMAKE_C_LINK_MODE
             \ CMAKE_C_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_C_OUTPUT_EXTENSION
             \ CMAKE_C_PLATFORM_ID
@@ -1136,13 +1300,16 @@
             \ CMAKE_C_STANDARD
             \ CMAKE_C_STANDARD_DEFAULT
             \ CMAKE_C_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_C_STANDARD_LATEST
             \ CMAKE_C_STANDARD_LIBRARIES
+            \ CMAKE_C_STANDARD_LINK_DIRECTORIES
             \ CMAKE_C_STANDARD_REQUIRED
             \ CMAKE_C_SUPPORTED
+            \ CMAKE_C_USING_LINKER_MODE
             \ CMAKE_C_VISIBILITY_PRESET
+            \ CMAKE_DEBUGGER_WORKING_DIRECTORY
             \ CMAKE_DEBUG_POSTFIX
             \ CMAKE_DEBUG_TARGET_PROPERTIES
-            \ CMAKE_DEBUGGER_WORKING_DIRECTORY
             \ CMAKE_DEFAULT_BUILD_TYPE
             \ CMAKE_DEFAULT_CONFIGS
             \ CMAKE_DEPENDS_IN_PROJECT_ONLY
@@ -1178,16 +1345,20 @@
             \ CMAKE_EXECUTABLE_SUFFIX_RC
             \ CMAKE_EXECUTABLE_SUFFIX_Swift
             \ CMAKE_EXECUTE_PROCESS_COMMAND_ECHO
+            \ CMAKE_EXECUTE_PROCESS_COMMAND_ERROR_IS_FATAL
             \ CMAKE_EXE_LINKER_FLAGS
             \ CMAKE_EXE_LINKER_FLAGS_INIT
+            \ CMAKE_EXPORT_BUILD_DATABASE
             \ CMAKE_EXPORT_COMPILE_COMMANDS
-            \ CMAKE_EXPORT_SARIF
+            \ CMAKE_EXPORT_FIND_PACKAGE_NAME
             \ CMAKE_EXPORT_NO_PACKAGE_REGISTRY
             \ CMAKE_EXPORT_PACKAGE_REGISTRY
+            \ CMAKE_EXPORT_SARIF
             \ CMAKE_EXTRA_GENERATOR
             \ CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES
             \ CMAKE_FIND_APPBUNDLE
             \ CMAKE_FIND_DEBUG_MODE
+            \ CMAKE_FIND_DEBUG_MODE_NO_IMPLICIT_CONFIGURE_LOG
             \ CMAKE_FIND_FRAMEWORK
             \ CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX
             \ CMAKE_FIND_LIBRARY_PREFIXES
@@ -1203,13 +1374,13 @@
             \ CMAKE_FIND_PACKAGE_SORT_ORDER
             \ CMAKE_FIND_PACKAGE_TARGETS_GLOBAL
             \ CMAKE_FIND_PACKAGE_WARN_NO_MODULE
+            \ CMAKE_FIND_REQUIRED
             \ CMAKE_FIND_ROOT_PATH
             \ CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
             \ CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
             \ CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
             \ CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
             \ CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH
-            \ CMAKE_FIND_USE_INSTALL_PREFIX
             \ CMAKE_FIND_USE_CMAKE_PATH
             \ CMAKE_FIND_USE_CMAKE_SYSTEM_PATH
             \ CMAKE_FIND_USE_INSTALL_PREFIX
@@ -1224,9 +1395,12 @@
             \ CMAKE_Fortran_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_Fortran_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_Fortran_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_Fortran_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_Fortran_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_Fortran_ARCHIVE_APPEND
             \ CMAKE_Fortran_ARCHIVE_CREATE
             \ CMAKE_Fortran_ARCHIVE_FINISH
+            \ CMAKE_Fortran_ATTRIBUTES
             \ CMAKE_Fortran_BYTE_ORDER
             \ CMAKE_Fortran_CLANG_TIDY
             \ CMAKE_Fortran_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -1238,6 +1412,10 @@
             \ CMAKE_Fortran_COMPILER_FRONTEND_VARIANT
             \ CMAKE_Fortran_COMPILER_ID
             \ CMAKE_Fortran_COMPILER_LAUNCHER
+            \ CMAKE_Fortran_COMPILER_LINKER
+            \ CMAKE_Fortran_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_Fortran_COMPILER_LINKER_ID
+            \ CMAKE_Fortran_COMPILER_LINKER_VERSION
             \ CMAKE_Fortran_COMPILER_LOADED
             \ CMAKE_Fortran_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_Fortran_COMPILER_RANLIB
@@ -1248,8 +1426,10 @@
             \ CMAKE_Fortran_CPPCHECK
             \ CMAKE_Fortran_CPPLINT
             \ CMAKE_Fortran_CREATE_SHARED_LIBRARY
+            \ CMAKE_Fortran_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_Fortran_CREATE_SHARED_MODULE
             \ CMAKE_Fortran_CREATE_STATIC_LIBRARY
+            \ CMAKE_Fortran_DEVICE_LINK_MODE
             \ CMAKE_Fortran_EXTENSIONS
             \ CMAKE_Fortran_EXTENSIONS_DEFAULT
             \ CMAKE_Fortran_FLAGS
@@ -1263,6 +1443,10 @@
             \ CMAKE_Fortran_FLAGS_RELWITHDEBINFO
             \ CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT
             \ CMAKE_Fortran_FORMAT
+            \ CMAKE_Fortran_HOST_COMPILER
+            \ CMAKE_Fortran_HOST_COMPILER_ID
+            \ CMAKE_Fortran_HOST_COMPILER_VERSION
+            \ CMAKE_Fortran_ICSTAT
             \ CMAKE_Fortran_IGNORE_EXTENSIONS
             \ CMAKE_Fortran_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES
@@ -1276,10 +1460,12 @@
             \ CMAKE_Fortran_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_Fortran_LINKER_WRAPPER_FLAG
             \ CMAKE_Fortran_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_Fortran_LINK_DEF_FILE_FLAG
             \ CMAKE_Fortran_LINK_EXECUTABLE
             \ CMAKE_Fortran_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_Fortran_LINK_LIBRARY_FLAG
             \ CMAKE_Fortran_LINK_LIBRARY_SUFFIX
+            \ CMAKE_Fortran_LINK_MODE
             \ CMAKE_Fortran_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_Fortran_MODDIR_DEFAULT
             \ CMAKE_Fortran_MODDIR_FLAG
@@ -1295,9 +1481,12 @@
             \ CMAKE_Fortran_STANDARD
             \ CMAKE_Fortran_STANDARD_DEFAULT
             \ CMAKE_Fortran_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_Fortran_STANDARD_LATEST
             \ CMAKE_Fortran_STANDARD_LIBRARIES
+            \ CMAKE_Fortran_STANDARD_LINK_DIRECTORIES
             \ CMAKE_Fortran_STANDARD_REQUIRED
             \ CMAKE_Fortran_SUPPORTED
+            \ CMAKE_Fortran_USING_LINKER_MODE
             \ CMAKE_Fortran_VISIBILITY_PRESET
             \ CMAKE_GENERATOR
             \ CMAKE_GENERATOR_INSTANCE
@@ -1314,9 +1503,12 @@
             \ CMAKE_HIP_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_HIP_ANDROID_TOOLCHAIN_SUFFIX
             \ CMAKE_HIP_ARCHITECTURES
+            \ CMAKE_HIP_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_HIP_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_HIP_ARCHIVE_APPEND
             \ CMAKE_HIP_ARCHIVE_CREATE
             \ CMAKE_HIP_ARCHIVE_FINISH
+            \ CMAKE_HIP_ATTRIBUTES
             \ CMAKE_HIP_BYTE_ORDER
             \ CMAKE_HIP_CLANG_TIDY
             \ CMAKE_HIP_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -1328,6 +1520,10 @@
             \ CMAKE_HIP_COMPILER_FRONTEND_VARIANT
             \ CMAKE_HIP_COMPILER_ID
             \ CMAKE_HIP_COMPILER_LAUNCHER
+            \ CMAKE_HIP_COMPILER_LINKER
+            \ CMAKE_HIP_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_HIP_COMPILER_LINKER_ID
+            \ CMAKE_HIP_COMPILER_LINKER_VERSION
             \ CMAKE_HIP_COMPILER_LOADED
             \ CMAKE_HIP_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_HIP_COMPILER_RANLIB
@@ -1339,8 +1535,10 @@
             \ CMAKE_HIP_CPPCHECK
             \ CMAKE_HIP_CPPLINT
             \ CMAKE_HIP_CREATE_SHARED_LIBRARY
+            \ CMAKE_HIP_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_HIP_CREATE_SHARED_MODULE
             \ CMAKE_HIP_CREATE_STATIC_LIBRARY
+            \ CMAKE_HIP_DEVICE_LINK_MODE
             \ CMAKE_HIP_EXTENSIONS
             \ CMAKE_HIP_EXTENSIONS_DEFAULT
             \ CMAKE_HIP_FLAGS
@@ -1353,6 +1551,10 @@
             \ CMAKE_HIP_FLAGS_RELEASE_INIT
             \ CMAKE_HIP_FLAGS_RELWITHDEBINFO
             \ CMAKE_HIP_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_HIP_HOST_COMPILER
+            \ CMAKE_HIP_HOST_COMPILER_ID
+            \ CMAKE_HIP_HOST_COMPILER_VERSION
+            \ CMAKE_HIP_ICSTAT
             \ CMAKE_HIP_IGNORE_EXTENSIONS
             \ CMAKE_HIP_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_HIP_IMPLICIT_LINK_DIRECTORIES
@@ -1366,12 +1568,15 @@
             \ CMAKE_HIP_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_HIP_LINKER_WRAPPER_FLAG
             \ CMAKE_HIP_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_HIP_LINK_DEF_FILE_FLAG
             \ CMAKE_HIP_LINK_EXECUTABLE
             \ CMAKE_HIP_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_HIP_LINK_LIBRARY_FLAG
             \ CMAKE_HIP_LINK_LIBRARY_SUFFIX
+            \ CMAKE_HIP_LINK_MODE
             \ CMAKE_HIP_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_HIP_OUTPUT_EXTENSION
+            \ CMAKE_HIP_PLATFORM
             \ CMAKE_HIP_PLATFORM_ID
             \ CMAKE_HIP_SIMULATE_ID
             \ CMAKE_HIP_SIMULATE_VERSION
@@ -1380,13 +1585,18 @@
             \ CMAKE_HIP_STANDARD
             \ CMAKE_HIP_STANDARD_DEFAULT
             \ CMAKE_HIP_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_HIP_STANDARD_LATEST
             \ CMAKE_HIP_STANDARD_LIBRARIES
+            \ CMAKE_HIP_STANDARD_LINK_DIRECTORIES
             \ CMAKE_HIP_STANDARD_REQUIRED
             \ CMAKE_HIP_SUPPORTED
+            \ CMAKE_HIP_USING_LINKER_MODE
             \ CMAKE_HIP_VISIBILITY_PRESET
             \ CMAKE_HOME_DIRECTORY
+            \ CMAKE_HOST_AIX
             \ CMAKE_HOST_APPLE
             \ CMAKE_HOST_BSD
+            \ CMAKE_HOST_EXECUTABLE_SUFFIX
             \ CMAKE_HOST_LINUX
             \ CMAKE_HOST_SOLARIS
             \ CMAKE_HOST_SYSTEM
@@ -1427,9 +1637,12 @@
             \ CMAKE_Java_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_Java_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_Java_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_Java_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_Java_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_Java_ARCHIVE_APPEND
             \ CMAKE_Java_ARCHIVE_CREATE
             \ CMAKE_Java_ARCHIVE_FINISH
+            \ CMAKE_Java_ATTRIBUTES
             \ CMAKE_Java_BYTE_ORDER
             \ CMAKE_Java_CLANG_TIDY
             \ CMAKE_Java_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -1441,6 +1654,10 @@
             \ CMAKE_Java_COMPILER_FRONTEND_VARIANT
             \ CMAKE_Java_COMPILER_ID
             \ CMAKE_Java_COMPILER_LAUNCHER
+            \ CMAKE_Java_COMPILER_LINKER
+            \ CMAKE_Java_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_Java_COMPILER_LINKER_ID
+            \ CMAKE_Java_COMPILER_LINKER_VERSION
             \ CMAKE_Java_COMPILER_LOADED
             \ CMAKE_Java_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_Java_COMPILER_RANLIB
@@ -1451,8 +1668,10 @@
             \ CMAKE_Java_CPPCHECK
             \ CMAKE_Java_CPPLINT
             \ CMAKE_Java_CREATE_SHARED_LIBRARY
+            \ CMAKE_Java_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_Java_CREATE_SHARED_MODULE
             \ CMAKE_Java_CREATE_STATIC_LIBRARY
+            \ CMAKE_Java_DEVICE_LINK_MODE
             \ CMAKE_Java_EXTENSIONS
             \ CMAKE_Java_EXTENSIONS_DEFAULT
             \ CMAKE_Java_FLAGS
@@ -1465,6 +1684,10 @@
             \ CMAKE_Java_FLAGS_RELEASE_INIT
             \ CMAKE_Java_FLAGS_RELWITHDEBINFO
             \ CMAKE_Java_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_Java_HOST_COMPILER
+            \ CMAKE_Java_HOST_COMPILER_ID
+            \ CMAKE_Java_HOST_COMPILER_VERSION
+            \ CMAKE_Java_ICSTAT
             \ CMAKE_Java_IGNORE_EXTENSIONS
             \ CMAKE_Java_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_Java_IMPLICIT_LINK_DIRECTORIES
@@ -1478,10 +1701,12 @@
             \ CMAKE_Java_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_Java_LINKER_WRAPPER_FLAG
             \ CMAKE_Java_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_Java_LINK_DEF_FILE_FLAG
             \ CMAKE_Java_LINK_EXECUTABLE
             \ CMAKE_Java_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_Java_LINK_LIBRARY_FLAG
             \ CMAKE_Java_LINK_LIBRARY_SUFFIX
+            \ CMAKE_Java_LINK_MODE
             \ CMAKE_Java_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_Java_OUTPUT_EXTENSION
             \ CMAKE_Java_PLATFORM_ID
@@ -1492,9 +1717,12 @@
             \ CMAKE_Java_STANDARD
             \ CMAKE_Java_STANDARD_DEFAULT
             \ CMAKE_Java_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_Java_STANDARD_LATEST
             \ CMAKE_Java_STANDARD_LIBRARIES
+            \ CMAKE_Java_STANDARD_LINK_DIRECTORIES
             \ CMAKE_Java_STANDARD_REQUIRED
             \ CMAKE_Java_SUPPORTED
+            \ CMAKE_Java_USING_LINKER_MODE
             \ CMAKE_Java_VISIBILITY_PRESET
             \ CMAKE_KATE_FILES_MODE
             \ CMAKE_KATE_MAKE_ARGUMENTS
@@ -1503,19 +1731,23 @@
             \ CMAKE_LIBRARY_OUTPUT_DIRECTORY
             \ CMAKE_LIBRARY_PATH
             \ CMAKE_LIBRARY_PATH_FLAG
+            \ CMAKE_LINKER_TYPE
             \ CMAKE_LINK_DEF_FILE_FLAG
             \ CMAKE_LINK_DEPENDS_NO_SHARED
             \ CMAKE_LINK_DEPENDS_USE_LINKER
             \ CMAKE_LINK_DIRECTORIES_BEFORE
             \ CMAKE_LINK_INTERFACE_LIBRARIES
             \ CMAKE_LINK_LIBRARIES_ONLY_TARGETS
+            \ CMAKE_LINK_LIBRARIES_STRATEGY
             \ CMAKE_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_LINK_LIBRARY_FLAG
             \ CMAKE_LINK_LIBRARY_SUFFIX
             \ CMAKE_LINK_SEARCH_END_STATIC
             \ CMAKE_LINK_SEARCH_START_STATIC
+            \ CMAKE_LINK_WARNING_AS_ERROR
             \ CMAKE_LINK_WHAT_YOU_USE
             \ CMAKE_LINK_WHAT_YOU_USE_CHECK
+            \ CMAKE_LIST_FILE_NAME
             \ CMAKE_MACOSX_BUNDLE
             \ CMAKE_MACOSX_RPATH
             \ CMAKE_MAJOR_VERSION
@@ -1552,6 +1784,7 @@
             \ CMAKE_OBJC_LINKER_LAUNCHER
             \ CMAKE_OBJC_STANDARD
             \ CMAKE_OBJC_STANDARD_REQUIRED
+            \ CMAKE_OBJDUMP
             \ CMAKE_OBJECT_PATH_MAX
             \ CMAKE_OPTIMIZE_DEPENDENCIES
             \ CMAKE_OSX_ARCHITECTURES
@@ -1562,15 +1795,23 @@
             \ CMAKE_PCH_INSTANTIATE_TEMPLATES
             \ CMAKE_PCH_WARN_INVALID
             \ CMAKE_PDB_OUTPUT_DIRECTORY
+            \ CMAKE_PKG_CONFIG_DISABLE_UNINSTALLED
+            \ CMAKE_PKG_CONFIG_PC_LIB_DIRS
+            \ CMAKE_PKG_CONFIG_PC_PATH
+            \ CMAKE_PKG_CONFIG_SYSROOT_DIR
+            \ CMAKE_PKG_CONFIG_TOP_BUILD_DIR
             \ CMAKE_PLATFORM_NO_VERSIONED_SONAME
+            \ CMAKE_POLICY_VERSION_MINIMUM
             \ CMAKE_POSITION_INDEPENDENT_CODE
             \ CMAKE_PREFIX_PATH
             \ CMAKE_PROGRAM_PATH
+            \ CMAKE_PROJECT_COMPAT_VERSION
             \ CMAKE_PROJECT_DESCRIPTION
             \ CMAKE_PROJECT_HOMEPAGE_URL
             \ CMAKE_PROJECT_INCLUDE
             \ CMAKE_PROJECT_INCLUDE_BEFORE
             \ CMAKE_PROJECT_NAME
+            \ CMAKE_PROJECT_SPDX_LICENSE
             \ CMAKE_PROJECT_TOP_LEVEL_INCLUDES
             \ CMAKE_PROJECT_VERSION
             \ CMAKE_PROJECT_VERSION_MAJOR
@@ -1582,9 +1823,12 @@
             \ CMAKE_RC_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_RC_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_RC_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_RC_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_RC_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_RC_ARCHIVE_APPEND
             \ CMAKE_RC_ARCHIVE_CREATE
             \ CMAKE_RC_ARCHIVE_FINISH
+            \ CMAKE_RC_ATTRIBUTES
             \ CMAKE_RC_BYTE_ORDER
             \ CMAKE_RC_CLANG_TIDY
             \ CMAKE_RC_CLANG_TIDY_EXPORT_FIXES_DIR
@@ -1596,6 +1840,10 @@
             \ CMAKE_RC_COMPILER_FRONTEND_VARIANT
             \ CMAKE_RC_COMPILER_ID
             \ CMAKE_RC_COMPILER_LAUNCHER
+            \ CMAKE_RC_COMPILER_LINKER
+            \ CMAKE_RC_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_RC_COMPILER_LINKER_ID
+            \ CMAKE_RC_COMPILER_LINKER_VERSION
             \ CMAKE_RC_COMPILER_LOADED
             \ CMAKE_RC_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_RC_COMPILER_RANLIB
@@ -1606,8 +1854,10 @@
             \ CMAKE_RC_CPPCHECK
             \ CMAKE_RC_CPPLINT
             \ CMAKE_RC_CREATE_SHARED_LIBRARY
+            \ CMAKE_RC_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_RC_CREATE_SHARED_MODULE
             \ CMAKE_RC_CREATE_STATIC_LIBRARY
+            \ CMAKE_RC_DEVICE_LINK_MODE
             \ CMAKE_RC_EXTENSIONS
             \ CMAKE_RC_EXTENSIONS_DEFAULT
             \ CMAKE_RC_FLAGS
@@ -1620,6 +1870,10 @@
             \ CMAKE_RC_FLAGS_RELEASE_INIT
             \ CMAKE_RC_FLAGS_RELWITHDEBINFO
             \ CMAKE_RC_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_RC_HOST_COMPILER
+            \ CMAKE_RC_HOST_COMPILER_ID
+            \ CMAKE_RC_HOST_COMPILER_VERSION
+            \ CMAKE_RC_ICSTAT
             \ CMAKE_RC_IGNORE_EXTENSIONS
             \ CMAKE_RC_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_RC_IMPLICIT_LINK_DIRECTORIES
@@ -1633,10 +1887,12 @@
             \ CMAKE_RC_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_RC_LINKER_WRAPPER_FLAG
             \ CMAKE_RC_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_RC_LINK_DEF_FILE_FLAG
             \ CMAKE_RC_LINK_EXECUTABLE
             \ CMAKE_RC_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_RC_LINK_LIBRARY_FLAG
             \ CMAKE_RC_LINK_LIBRARY_SUFFIX
+            \ CMAKE_RC_LINK_MODE
             \ CMAKE_RC_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_RC_OUTPUT_EXTENSION
             \ CMAKE_RC_PLATFORM_ID
@@ -1647,14 +1903,18 @@
             \ CMAKE_RC_STANDARD
             \ CMAKE_RC_STANDARD_DEFAULT
             \ CMAKE_RC_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_RC_STANDARD_LATEST
             \ CMAKE_RC_STANDARD_LIBRARIES
+            \ CMAKE_RC_STANDARD_LINK_DIRECTORIES
             \ CMAKE_RC_STANDARD_REQUIRED
             \ CMAKE_RC_SUPPORTED
+            \ CMAKE_RC_USING_LINKER_MODE
             \ CMAKE_RC_VISIBILITY_PRESET
             \ CMAKE_ROOT
             \ CMAKE_RULE_MESSAGES
             \ CMAKE_RUNTIME_OUTPUT_DIRECTORY
             \ CMAKE_SCRIPT_MODE_FILE
+            \ CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX
             \ CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS
             \ CMAKE_SHARED_LIBRARY_PREFIX
             \ CMAKE_SHARED_LIBRARY_SUFFIX
@@ -1697,12 +1957,16 @@
             \ CMAKE_Swift_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_Swift_ANDROID_TOOLCHAIN_PREFIX
             \ CMAKE_Swift_ANDROID_TOOLCHAIN_SUFFIX
+            \ CMAKE_Swift_ARCHIVER_WRAPPER_FLAG
+            \ CMAKE_Swift_ARCHIVER_WRAPPER_FLAG_SEP
             \ CMAKE_Swift_ARCHIVE_APPEND
             \ CMAKE_Swift_ARCHIVE_CREATE
             \ CMAKE_Swift_ARCHIVE_FINISH
+            \ CMAKE_Swift_ATTRIBUTES
             \ CMAKE_Swift_BYTE_ORDER
             \ CMAKE_Swift_CLANG_TIDY
             \ CMAKE_Swift_CLANG_TIDY_EXPORT_FIXES_DIR
+            \ CMAKE_Swift_COMPILATION_MODE
             \ CMAKE_Swift_COMPILER
             \ CMAKE_Swift_COMPILER_ABI
             \ CMAKE_Swift_COMPILER_AR
@@ -1711,6 +1975,10 @@
             \ CMAKE_Swift_COMPILER_FRONTEND_VARIANT
             \ CMAKE_Swift_COMPILER_ID
             \ CMAKE_Swift_COMPILER_LAUNCHER
+            \ CMAKE_Swift_COMPILER_LINKER
+            \ CMAKE_Swift_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CMAKE_Swift_COMPILER_LINKER_ID
+            \ CMAKE_Swift_COMPILER_LINKER_VERSION
             \ CMAKE_Swift_COMPILER_LOADED
             \ CMAKE_Swift_COMPILER_PREDEFINES_COMMAND
             \ CMAKE_Swift_COMPILER_RANLIB
@@ -1721,8 +1989,10 @@
             \ CMAKE_Swift_CPPCHECK
             \ CMAKE_Swift_CPPLINT
             \ CMAKE_Swift_CREATE_SHARED_LIBRARY
+            \ CMAKE_Swift_CREATE_SHARED_LIBRARY_ARCHIVE
             \ CMAKE_Swift_CREATE_SHARED_MODULE
             \ CMAKE_Swift_CREATE_STATIC_LIBRARY
+            \ CMAKE_Swift_DEVICE_LINK_MODE
             \ CMAKE_Swift_EXTENSIONS
             \ CMAKE_Swift_EXTENSIONS_DEFAULT
             \ CMAKE_Swift_FLAGS
@@ -1735,6 +2005,10 @@
             \ CMAKE_Swift_FLAGS_RELEASE_INIT
             \ CMAKE_Swift_FLAGS_RELWITHDEBINFO
             \ CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT
+            \ CMAKE_Swift_HOST_COMPILER
+            \ CMAKE_Swift_HOST_COMPILER_ID
+            \ CMAKE_Swift_HOST_COMPILER_VERSION
+            \ CMAKE_Swift_ICSTAT
             \ CMAKE_Swift_IGNORE_EXTENSIONS
             \ CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES
             \ CMAKE_Swift_IMPLICIT_LINK_DIRECTORIES
@@ -1749,10 +2023,12 @@
             \ CMAKE_Swift_LINKER_PREFERENCE_PROPAGATES
             \ CMAKE_Swift_LINKER_WRAPPER_FLAG
             \ CMAKE_Swift_LINKER_WRAPPER_FLAG_SEP
+            \ CMAKE_Swift_LINK_DEF_FILE_FLAG
             \ CMAKE_Swift_LINK_EXECUTABLE
             \ CMAKE_Swift_LINK_LIBRARY_FILE_FLAG
             \ CMAKE_Swift_LINK_LIBRARY_FLAG
             \ CMAKE_Swift_LINK_LIBRARY_SUFFIX
+            \ CMAKE_Swift_LINK_MODE
             \ CMAKE_Swift_LINK_WHAT_YOU_USE_FLAG
             \ CMAKE_Swift_MODULE_DIRECTORY
             \ CMAKE_Swift_NUM_THREADS
@@ -1765,13 +2041,18 @@
             \ CMAKE_Swift_STANDARD
             \ CMAKE_Swift_STANDARD_DEFAULT
             \ CMAKE_Swift_STANDARD_INCLUDE_DIRECTORIES
+            \ CMAKE_Swift_STANDARD_LATEST
             \ CMAKE_Swift_STANDARD_LIBRARIES
+            \ CMAKE_Swift_STANDARD_LINK_DIRECTORIES
             \ CMAKE_Swift_STANDARD_REQUIRED
             \ CMAKE_Swift_SUPPORTED
+            \ CMAKE_Swift_USING_LINKER_MODE
             \ CMAKE_Swift_VISIBILITY_PRESET
             \ CMAKE_TASKING_TOOLSET
+            \ CMAKE_TEST_LAUNCHER
             \ CMAKE_TLS_CAINFO
             \ CMAKE_TLS_VERIFY
+            \ CMAKE_TLS_VERSION
             \ CMAKE_TOOLCHAIN_FILE
             \ CMAKE_TRY_COMPILE_CONFIGURATION
             \ CMAKE_TRY_COMPILE_NO_PLATFORM_VARIABLES
@@ -1780,6 +2061,7 @@
             \ CMAKE_TWEAK_VERSION
             \ CMAKE_UNITY_BUILD
             \ CMAKE_UNITY_BUILD_BATCH_SIZE
+            \ CMAKE_UNITY_BUILD_RELOCATABLE
             \ CMAKE_UNITY_BUILD_UNIQUE_ID
             \ CMAKE_USER_MAKE_RULES_OVERRIDE
             \ CMAKE_USER_MAKE_RULES_OVERRIDE_ASM
@@ -1818,6 +2100,7 @@
             \ CMAKE_VS_PLATFORM_TOOLSET
             \ CMAKE_VS_PLATFORM_TOOLSET_CUDA
             \ CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR
+            \ CMAKE_VS_PLATFORM_TOOLSET_FORTRAN
             \ CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE
             \ CMAKE_VS_PLATFORM_TOOLSET_VERSION
             \ CMAKE_VS_SDK_EXCLUDE_DIRECTORIES
@@ -1830,6 +2113,7 @@
             \ CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER
             \ CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION
             \ CMAKE_VS_TARGET_FRAMEWORK_VERSION
+            \ CMAKE_VS_USE_DEBUG_LIBRARIES
             \ CMAKE_VS_VERSION_BUILD_NUMBER
             \ CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION
             \ CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION
@@ -1840,6 +2124,7 @@
             \ CMAKE_WATCOM_RUNTIME_LIBRARY
             \ CMAKE_WIN32_EXECUTABLE
             \ CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS
+            \ CMAKE_WINDOWS_KMDF_VERSION
             \ CMAKE_XCODE_BUILD_SYSTEM
             \ CMAKE_XCODE_GENERATE_SCHEME
             \ CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY
@@ -1848,28 +2133,26 @@
             \ CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER
             \ CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN
             \ CMAKE_XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING
-            \ CMAKE_XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE
             \ CMAKE_XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER
             \ CMAKE_XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS
             \ CMAKE_XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE
             \ CMAKE_XCODE_SCHEME_ENABLE_GPU_API_VALIDATION
+            \ CMAKE_XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE
             \ CMAKE_XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION
             \ CMAKE_XCODE_SCHEME_ENVIRONMENT
             \ CMAKE_XCODE_SCHEME_GUARD_MALLOC
+            \ CMAKE_XCODE_SCHEME_LAUNCH_CONFIGURATION
             \ CMAKE_XCODE_SCHEME_LAUNCH_MODE
             \ CMAKE_XCODE_SCHEME_LLDB_INIT_FILE
             \ CMAKE_XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP
             \ CMAKE_XCODE_SCHEME_MALLOC_GUARD_EDGES
             \ CMAKE_XCODE_SCHEME_MALLOC_SCRIBBLE
             \ CMAKE_XCODE_SCHEME_MALLOC_STACK
+            \ CMAKE_XCODE_SCHEME_TEST_CONFIGURATION
             \ CMAKE_XCODE_SCHEME_THREAD_SANITIZER
             \ CMAKE_XCODE_SCHEME_THREAD_SANITIZER_STOP
             \ CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER
             \ CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP
-            \ CMAKE_XCODE_SCHEME_ENABLE_GPU_API_VALIDATION
-            \ CMAKE_XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION
-            \ CMAKE_XCODE_SCHEME_LAUNCH_CONFIGURATION
-            \ CMAKE_XCODE_SCHEME_TEST_CONFIGURATION
             \ CMAKE_XCODE_SCHEME_WORKING_DIRECTORY
             \ CMAKE_XCODE_SCHEME_ZOMBIE_OBJECTS
             \ CMAKE_XCODE_XCCONFIG
@@ -1903,7 +2186,6 @@
             \ CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS
             \ CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS
             \ CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE
-            \ CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION
             \ CTEST_CUSTOM_MEMCHECK_IGNORE
             \ CTEST_CUSTOM_POST_MEMCHECK
             \ CTEST_CUSTOM_POST_TEST
@@ -1923,6 +2205,7 @@
             \ CTEST_DROP_SITE_PASSWORD
             \ CTEST_DROP_SITE_USER
             \ CTEST_EXTRA_COVERAGE_GLOB
+            \ CTEST_EXTRA_SUBMIT_FILES
             \ CTEST_GIT_COMMAND
             \ CTEST_GIT_INIT_SUBMODULES
             \ CTEST_GIT_UPDATE_CUSTOM
@@ -1936,6 +2219,7 @@
             \ CTEST_MEMORYCHECK_SUPPRESSIONS_FILE
             \ CTEST_MEMORYCHECK_TYPE
             \ CTEST_NIGHTLY_START_TIME
+            \ CTEST_NOTES_FILES
             \ CTEST_P4_CLIENT
             \ CTEST_P4_COMMAND
             \ CTEST_P4_OPTIONS
@@ -1953,6 +2237,8 @@
             \ CTEST_SVN_UPDATE_OPTIONS
             \ CTEST_TEST_LOAD
             \ CTEST_TEST_TIMEOUT
+            \ CTEST_TLS_VERIFY
+            \ CTEST_TLS_VERSION
             \ CTEST_TRIGGER_SITE
             \ CTEST_UPDATE_COMMAND
             \ CTEST_UPDATE_OPTIONS
@@ -2226,6 +2512,7 @@
             \ DOXYGEN_USE_PDFLATEX
             \ DOXYGEN_VERBATIM_HEADERS
             \ DOXYGEN_VERBATIM_VARS
+            \ Doxygen_VERSION
             \ DOXYGEN_VERSION
             \ DOXYGEN_WARNINGS
             \ DOXYGEN_WARN_AS_ERROR
@@ -2259,17 +2546,20 @@
             \ MSVC_VERSION
             \ MSYS
             \ PROJECT_BINARY_DIR
+            \ PROJECT_COMPAT_VERSION
             \ PROJECT_DESCRIPTION
             \ PROJECT_HOMEPAGE_URL
             \ PROJECT_IS_TOP_LEVEL
             \ PROJECT_NAME
             \ PROJECT_SOURCE_DIR
+            \ PROJECT_SPDX_LICENSE
             \ PROJECT_VERSION
             \ PROJECT_VERSION_MAJOR
             \ PROJECT_VERSION_MINOR
             \ PROJECT_VERSION_PATCH
             \ PROJECT_VERSION_TWEAK
             \ UNIX
+            \ WASI
             \ WIN32
             \ WINCE
             \ WINDOWS_PHONE
@@ -2287,7 +2577,9 @@
             \ BUILD_ALWAYS
             \ BUILD_BYPRODUCTS
             \ BUILD_COMMAND
+            \ BUILD_ENVIRONMENT_MODIFICATION
             \ BUILD_IN_SOURCE
+            \ BUILD_JOB_SERVER_AWARE
             \ CHECKOUT
             \ CMAKE_ARGS
             \ CMAKE_CACHE_ARGS
@@ -2296,12 +2588,14 @@
             \ CMAKE_INSTALL_MODE
             \ COMMENT
             \ CONFIGURE_COMMAND
+            \ CONFIGURE_ENVIRONMENT_MODIFICATION
             \ CONFIGURE_HANDLED_BY_BUILD
             \ CVS
             \ CVSROOT
             \ CVS_MODULE
             \ CVS_REPOSITORY
             \ CVS_TAG
+            \ DCMAKE_PREFIX_PATH
             \ DEPENDEES
             \ DEPENDERS
             \ DEPENDS
@@ -2341,7 +2635,8 @@
             \ INSTALL_BYPRODUCTS
             \ INSTALL_COMMAND
             \ INSTALL_DIR
-            \ JOB_POOLS
+            \ INSTALL_ENVIRONMENT_MODIFICATION
+            \ INSTALL_JOB_SERVER_AWARE
             \ LIST_SEPARATOR
             \ LOG_BUILD
             \ LOG_CONFIGURE
@@ -2380,10 +2675,12 @@
             \ TEST_AFTER_INSTALL
             \ TEST_BEFORE_INSTALL
             \ TEST_COMMAND
+            \ TEST_ENVIRONMENT_MODIFICATION
             \ TEST_EXCLUDE_FROM_MAIN
             \ TIMEOUT
             \ TLS_CAINFO
             \ TLS_VERIFY
+            \ TLS_VERSION
             \ TMP_DIR
             \ TRUE
             \ UPDATE_COMMAND
@@ -2407,11 +2704,10 @@
             \ BYPASS_PROVIDER
             \ CMAKE_PROJECT_
             \ CONFIGURE_COMMAND
-            \ COPY
             \ CORRECT
             \ DCMAKE_TOOLCHAIN_FILE
-            \ DESTINATION
             \ DOWNLOAD_NO_EXTRACT
+            \ EXCLUDE_FROM_ALL
             \ EXISTS
             \ FETCHCONTENT_BASE_DIR
             \ FETCHCONTENT_FULLY_DISCONNECTED
@@ -2433,6 +2729,7 @@
             \ NAME
             \ NAMES
             \ NEVER
+            \ NOT
             \ NOTE
             \ OFF
             \ OPTIONAL
@@ -2441,6 +2738,7 @@
             \ PACKAGE_VERSION_COMPATIBLE
             \ PACKAGE_VERSION_EXACT
             \ QUIET
+            \ REQUIRED
             \ SOURCE_SUBDIR
             \ STREQUAL
             \ SUBBUILD_DIR
@@ -2449,10 +2747,10 @@
             \ SYSTEM
             \ TARGET
             \ TEST_COMMAND
-            \ TRUE
             \ URL
             \ URL_HASH
             \ VERIFY_INTERFACE_HEADER_SETS
+            \ WARNING
             \ WRITE
             \ WRONG
             \ _BINARY_DIR
@@ -2475,11 +2773,13 @@
             \ _FLAGS_
 
 syn keyword cmakeKWadd_custom_command contained
+            \ ALIAS
             \ APPEND
             \ ARGS
             \ BNF
             \ BYPRODUCTS
             \ CC
+            \ CODEGEN
             \ COMMAND
             \ COMMAND_EXPAND_LISTS
             \ COMMENT
@@ -2493,11 +2793,14 @@
             \ INCLUDE_DIRECTORIES
             \ JOB_POOL
             \ JOB_POOLS
+            \ JOB_SERVER_AWARE
             \ JOIN
             \ MAIN_DEPENDENCY
             \ MODULE
             \ NOT
+            \ OPTIMIZE_DEPENDENCIES
             \ OUTPUT
+            \ OUTPUTS
             \ PATH
             \ POST_BUILD
             \ PRE_BUILD
@@ -2525,6 +2828,7 @@
             \ INCLUDE_DIRECTORIES
             \ JOB_POOL
             \ JOB_POOLS
+            \ JOB_SERVER_AWARE
             \ JOIN
             \ PATH
             \ SOURCES
@@ -2542,6 +2846,7 @@
 
 syn keyword cmakeKWadd_dependencies contained
             \ DEPENDS
+            \ MANUALLY_ADDED_DEPENDENCIES
             \ OBJECT_DEPENDS
 
 syn keyword cmakeKWadd_executable contained
@@ -2573,7 +2878,6 @@
             \ HEADER_FILE_ONLY
             \ HEADER_SETS
             \ IMPORTED
-            \ IMPORTED_
             \ IMPORTED_IMPLIB
             \ IMPORTED_IMPLIB_
             \ IMPORTED_LOCATION
@@ -2589,7 +2893,6 @@
             \ LIBRARY_OUTPUT_DIRECTORY
             \ MODULE
             \ OBJECT
-            \ ON
             \ OUTPUT_NAME
             \ POSITION_INDEPENDENT_CODE
             \ POST_BUILD
@@ -2631,22 +2934,25 @@
             \ SYSTEM
 
 syn keyword cmakeKWadd_test contained
-            \ BUILD_TESTING
             \ COMMAND
             \ COMMAND_EXPAND_LISTS
             \ CONFIGURATIONS
+            \ CROSSCOMPILING_EMULATOR
             \ FAIL_REGULAR_EXPRESSION
             \ NAME
             \ OFF
             \ PASS_REGULAR_EXPRESSION
             \ SKIP_REGULAR_EXPRESSION
             \ TARGET_FILE
+            \ TEST
+            \ TEST_LAUNCHER
             \ WILL_FAIL
             \ WORKING_DIRECTORY
 
 syn keyword cmakeKWblock contained
             \ PARENT_SCOPE
             \ POLICIES
+            \ POP
             \ PROPAGATE
             \ PUSH
             \ SCOPE_FOR
@@ -2723,6 +3029,7 @@
             \ LISTS
             \ LTS
             \ MATCHES
+            \ MSYSTEM_PREFIX
             \ NNN
             \ NOT
             \ NUMBER_OF_LOGICAL_CORES
@@ -2755,6 +3062,16 @@
             \ VIEW
             \ WINDOWS_REGISTRY
 
+syn keyword cmakeKWcmake_instrumentation contained
+            \ API
+            \ API_VERSION
+            \ CALLBACK
+            \ CMAKE_EXPERIMENTAL_INSTRUMENTATION
+            \ DATA_VERSION
+            \ HOOKS
+            \ JSON
+            \ QUERIES
+
 syn keyword cmakeKWcmake_language contained
             \ AND
             \ ANY
@@ -2771,6 +3088,7 @@
             \ DEFER
             \ DIRECTORY
             \ EVAL
+            \ EXIT
             \ FALSE
             \ FETCHCONTENT_MAKEAVAILABLE_SERIAL
             \ FETCHCONTENT_SOURCE_DIR_
@@ -2790,6 +3108,7 @@
             \ OVERRIDE_FIND_PACKAGE
             \ PATH
             \ POP_BACK
+            \ PROPAGATE_TOP_LEVEL_INCLUDES_TO_TRY_COMPILE
             \ QUIET
             \ SET_DEPENDENCY_PROVIDER
             \ SOURCE_DIR
@@ -2803,7 +3122,9 @@
             \ _PATH
 
 syn keyword cmakeKWcmake_minimum_required contained
+            \ CMAKE_POLICY_DEFAULT_CMP
             \ FATAL_ERROR
+            \ NNNN
             \ VERSION
 
 syn keyword cmakeKWcmake_parse_arguments contained
@@ -2813,21 +3134,13 @@
             \ FALSE
             \ FAST
             \ FILES
-            \ MY_INSTALL
-            \ MY_INSTALL_CONFIGURATIONS
-            \ MY_INSTALL_DESTINATION
-            \ MY_INSTALL_FAST
-            \ MY_INSTALL_KEYWORDS_MISSING_VALUES
-            \ MY_INSTALL_OPTIONAL
-            \ MY_INSTALL_RENAME
-            \ MY_INSTALL_TARGETS
-            \ MY_INSTALL_UNPARSED_ARGUMENTS
+            \ NOTE
             \ OPTIONAL
             \ PARSE_ARGV
             \ RENAME
             \ TARGETS
             \ TRUE
-            \ UNDEFINED
+            \ UNSET
             \ _KEYWORDS_MISSING_VALUES
             \ _UNPARSED_ARGUMENTS
 
@@ -2893,6 +3206,72 @@
             \ TRUE
             \ XOR
 
+syn keyword cmakeKWcmake_pkg_config contained
+            \ ALLOW_SYSTEM_INCLUDES
+            \ ALLOW_SYSTEM_LIBS
+            \ BEST_EFFORT
+            \ BIND_PC_REQUIRES
+            \ CMAKE_PKG_CONFIG_ALLOW_SYS_INCLUDES
+            \ CMAKE_PKG_CONFIG_ALLOW_SYS_LIBS
+            \ CMAKE_PKG_CONFIG_CFLAGS
+            \ CMAKE_PKG_CONFIG_COMPILE_OPTIONS
+            \ CMAKE_PKG_CONFIG_CONFLICTS
+            \ CMAKE_PKG_CONFIG_DESCRIPTION
+            \ CMAKE_PKG_CONFIG_INCLUDES
+            \ CMAKE_PKG_CONFIG_LIBDIRS
+            \ CMAKE_PKG_CONFIG_LIBNAMES
+            \ CMAKE_PKG_CONFIG_LIBS
+            \ CMAKE_PKG_CONFIG_LINK_OPTIONS
+            \ CMAKE_PKG_CONFIG_NAME
+            \ CMAKE_PKG_CONFIG_PKGCONF_INCLUDES
+            \ CMAKE_PKG_CONFIG_PKGCONF_LIB_DIRS
+            \ CMAKE_PKG_CONFIG_PROVIDES
+            \ CMAKE_PKG_CONFIG_REQUIRES
+            \ CMAKE_PKG_CONFIG_SYS_INCLUDE_DIRS
+            \ CMAKE_PKG_CONFIG_SYS_LIB_DIRS
+            \ CMAKE_PKG_CONFIG_VERSION
+            \ CPATH
+            \ CPLUS_INCLUDE_PATH
+            \ C_INCLUDE_PATH
+            \ DISABLE_UNINSTALLED
+            \ ENV_MODE
+            \ EXACT
+            \ EXTRACT
+            \ FDO
+            \ IGNORE
+            \ IMPORT
+            \ IMPORTED
+            \ INTERFACE_LINK_LIBRARIES
+            \ OBJC_INCLUDE_PATH
+            \ PC_LIBDIR
+            \ PC_PATH
+            \ PC_SYSROOT_DIR
+            \ PERMISSIVE
+            \ PKGCONF
+            \ PKGCONFIG_
+            \ PKG_CONFIG_
+            \ PKG_CONFIG_ALLOW_
+            \ PKG_CONFIG_ALLOW_SYSTEM_CFLAGS
+            \ PKG_CONFIG_ALLOW_SYSTEM_LIBS
+            \ PKG_CONFIG_DISABLE_UNINSTALLED
+            \ PKG_CONFIG_LIBDIR
+            \ PKG_CONFIG_PATH
+            \ PKG_CONFIG_SYSROOT_DIR
+            \ PKG_CONFIG_SYSROOT_PATH
+            \ PKG_CONFIG_SYSTEM_INCLUDE_PATH
+            \ PKG_CONFIG_SYSTEM_LIBRARY_PATH
+            \ PKG_CONFIG_TOP_BUILD_DIR
+            \ POPULATE
+            \ PREFIX
+            \ QUIET
+            \ REQUIRED
+            \ STRICTNESS
+            \ SYSTEM_INCLUDE_DIRS
+            \ SYSTEM_LIBRARY_DIRS
+            \ TOP_BUILD_DIR
+            \ _FOUND
+            \ _PRIVATE
+
 syn keyword cmakeKWcmake_policy contained
             \ CMAKE_POLICY_DEFAULT_CMP
             \ CMP
@@ -3011,8 +3390,6 @@
             \ CAPTURE_CMAKE_ERROR
             \ CDASH_UPLOAD
             \ CDASH_UPLOAD_TYPE
-            \ CTEST_EXTRA_SUBMIT_FILES
-            \ CTEST_NOTES_FILES
             \ FILES
             \ HTTPHEADER
             \ PARTS
@@ -3034,10 +3411,13 @@
             \ EXCLUDE_FIXTURE
             \ EXCLUDE_FIXTURE_CLEANUP
             \ EXCLUDE_FIXTURE_SETUP
+            \ EXCLUDE_FROM_FILE
             \ EXCLUDE_LABEL
             \ INCLUDE
+            \ INCLUDE_FROM_FILE
             \ INCLUDE_LABEL
             \ LABELS
+            \ NOT
             \ OFF
             \ ON
             \ OUTPUT_JUNIT
@@ -3074,11 +3454,14 @@
             \ BRIEF_DOCS
             \ CACHED_VARIABLE
             \ CMAKE_
+            \ DEFINED
             \ DIRECTORY
             \ FULL_DOCS
             \ GLOBAL
             \ INHERITED
             \ INITIALIZE_FROM_VARIABLE
+            \ MY_NEW_PROP
+            \ NONE
             \ PROPERTY
             \ SOURCE
             \ TARGET
@@ -3105,13 +3488,15 @@
             \ OBJCXX
             \ OPTIONAL
 
-syn keyword cmakeKWenable_testing contained
-            \ BUILD_TESTING
-
 syn keyword cmakeKWexec_program contained
             \ ARGS
+            \ COMMAND
+            \ ERROR_VARIABLE
+            \ OUTPUT_STRIP_TRAILING_WHITESPACE
             \ OUTPUT_VARIABLE
+            \ RESULT_VARIABLE
             \ RETURN_VALUE
+            \ WORKING_DIRECTORY
 
 syn keyword cmakeKWexecute_process contained
             \ ANSI
@@ -3148,17 +3533,43 @@
 syn keyword cmakeKWexport contained
             \ ANDROID_MK
             \ APPEND
+            \ APPENDIX
+            \ AUTO
+            \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES
+            \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO
+            \ CMAKE_MAP_IMPORTED_CONFIG_
+            \ COMPAT_VERSION
             \ CONFIG
+            \ CPS
             \ CXX_MODULES_DIRECTORY
+            \ DEFAULT_CONFIGURATIONS
+            \ DEFAULT_LICENSE
+            \ DEFAULT_TARGETS
+            \ DESCRIPTION
+            \ ENABLED
             \ EXPORT
             \ EXPORT_LINK_INTERFACE_LIBRARIES
+            \ EXPORT_PACKAGE_DEPENDENCIES
+            \ EXTRA_ARGS
             \ FILE
+            \ HOMEPAGE_URL
             \ IMPORTED_
+            \ LICENSE
+            \ LOWER_CASE_FILE
             \ NAMESPACE
             \ NDK
+            \ NO_PROJECT_METADATA
             \ OLD
             \ PACKAGE
+            \ PACKAGE_DEPENDENCY
+            \ PACKAGE_INFO
+            \ PROJECT
+            \ REQUIRED
+            \ SETUP
             \ TARGETS
+            \ VERSION
+            \ VERSION_SCHEMA
+            \ XCFRAMEWORK_LOCATION
 
 syn keyword cmakeKWexport_library_dependencies contained
             \ APPEND
@@ -3180,7 +3591,7 @@
             \ CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM
             \ CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL
             \ CMAKE_INSTALL_MODE
-            \ CMAKE_OBJDUMP
+            \ CMAKE_MATCH_
             \ CODE
             \ COMPILE_FEATURES
             \ COMPRESSION
@@ -3197,13 +3608,14 @@
             \ CREATE_LINK
             \ CRLF
             \ DESTINATION
-            \ DIRECTORIES
             \ DIRECTORY_PERMISSIONS
             \ DLL
             \ DOS
             \ DOWNLOAD
+            \ ELF
             \ ENCODING
             \ ESCAPE_QUOTES
+            \ EXCLUDE
             \ EXECUTABLES
             \ EXPAND_TILDE
             \ EXPECTED_HASH
@@ -3244,6 +3656,7 @@
             \ LOCK
             \ LOG
             \ MAKE_DIRECTORY
+            \ MATCHALL
             \ MODULES
             \ MTIME
             \ MYLIBRARY
@@ -3309,6 +3722,7 @@
             \ TIMESTAMP
             \ TLS_CAINFO
             \ TLS_VERIFY
+            \ TLS_VERSION
             \ TOUCH
             \ TOUCH_NOCREATE
             \ TO_CMAKE_PATH
@@ -3323,7 +3737,9 @@
             \ USE_SOURCE_PERMISSIONS
             \ UTC
             \ UTF
+            \ VAR
             \ VERBOSE
+            \ WORKING_DIRECTORY
             \ WORLD_EXECUTE
             \ WORLD_READ
             \ WORLD_WRITE
@@ -3339,7 +3755,9 @@
             \ DOC
             \ DVAR
             \ FALSE
+            \ FIND_XXX_ORDER
             \ FIND_XXX_REGISTRY_VIEW
+            \ FIND_XXX_ROOT
             \ HINTS
             \ HOST
             \ INCLUDE
@@ -3356,6 +3774,7 @@
             \ NO_PACKAGE_ROOT_PATH
             \ NO_SYSTEM_ENVIRONMENT_PATH
             \ ONLY_CMAKE_FIND_ROOT_PATH
+            \ OPTIONAL
             \ PACKAGENAME
             \ PARENT_SCOPE
             \ PATHS
@@ -3374,7 +3793,9 @@
             \ DOC
             \ DVAR
             \ FALSE
+            \ FIND_XXX_ORDER
             \ FIND_XXX_REGISTRY_VIEW
+            \ FIND_XXX_ROOT
             \ HINTS
             \ HOST
             \ LIB
@@ -3392,6 +3813,7 @@
             \ NO_PACKAGE_ROOT_PATH
             \ NO_SYSTEM_ENVIRONMENT_PATH
             \ ONLY_CMAKE_FIND_ROOT_PATH
+            \ OPTIONAL
             \ PACKAGENAME
             \ PARENT_SCOPE
             \ PATHS
@@ -3404,17 +3826,17 @@
 
 syn keyword cmakeKWfind_package contained
             \ ABI
+            \ ASC
             \ BOTH
             \ BUNDLE
             \ BYPASS_PROVIDER
             \ CATEGORY
             \ CMAKE_DISABLE_FIND_PACKAGE_
-            \ CMAKE_REQUIRE_FIND_PACKAGE_
+            \ CMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES
             \ CMAKE_FIND_ROOT_PATH_BOTH
             \ CMAKE_FIND_USE_
             \ CMAKE_REQUIRE_FIND_PACKAGE_
             \ COMPONENTS
-            \ CONFIG
             \ CONFIGS
             \ DEC
             \ DVAR
@@ -3422,6 +3844,7 @@
             \ EXCLUDE
             \ FALSE
             \ FIND_PACKAGE_VERSION_FORMAT
+            \ FIND_XXX_REGISTRY_VIEW
             \ FRAMEWORK
             \ GLOBAL
             \ HINTS
@@ -3430,6 +3853,7 @@
             \ MODULE
             \ NAMES
             \ NATURAL
+            \ NONE
             \ NO_CMAKE_BUILDS_PATH
             \ NO_CMAKE_ENVIRONMENT_PATH
             \ NO_CMAKE_FIND_ROOT_PATH
@@ -3443,8 +3867,8 @@
             \ NO_PACKAGE_ROOT_PATH
             \ NO_POLICY_SCOPE
             \ NO_SYSTEM_ENVIRONMENT_PATH
-            \ OLD
             \ ONLY_CMAKE_FIND_ROOT_PATH
+            \ OPTIONAL
             \ OPTIONAL_COMPONENTS
             \ PACKAGENAME
             \ PACKAGE_FIND_NAME
@@ -3477,7 +3901,6 @@
             \ QUIET
             \ REGISTRY_VIEW
             \ REQUIRED
-            \ SET
             \ TARGET
             \ TRUE
             \ VALUE
@@ -3501,7 +3924,9 @@
             \ DOC
             \ DVAR
             \ FALSE
+            \ FIND_XXX_ORDER
             \ FIND_XXX_REGISTRY_VIEW
+            \ FIND_XXX_ROOT
             \ HINTS
             \ HOST
             \ INCLUDE
@@ -3518,6 +3943,7 @@
             \ NO_PACKAGE_ROOT_PATH
             \ NO_SYSTEM_ENVIRONMENT_PATH
             \ ONLY_CMAKE_FIND_ROOT_PATH
+            \ OPTIONAL
             \ PACKAGENAME
             \ PARENT_SCOPE
             \ PATHS
@@ -3536,10 +3962,13 @@
             \ DOC
             \ DVAR
             \ FALSE
+            \ FIND_XXX_ORDER
             \ FIND_XXX_REGISTRY_VIEW
+            \ FIND_XXX_ROOT
             \ HINTS
             \ HOST
             \ MATCHES
+            \ MY_SCRIPT
             \ NAMES
             \ NAMES_PER_DIR
             \ NOT
@@ -3553,6 +3982,7 @@
             \ NO_PACKAGE_ROOT_PATH
             \ NO_SYSTEM_ENVIRONMENT_PATH
             \ ONLY_CMAKE_FIND_ROOT_PATH
+            \ OPTIONAL
             \ PACKAGENAME
             \ PARENT_SCOPE
             \ PATHS
@@ -3635,11 +4065,10 @@
 
 syn keyword cmakeKWget_target_property contained
             \ INHERITED
-            \ VAR
 
 syn keyword cmakeKWget_test_property contained
+            \ DIRECTORY
             \ INHERITED
-            \ VAR
 
 syn keyword cmakeKWif contained
             \ CMAKE_MATCH_
@@ -3656,15 +4085,17 @@
             \ IN_LIST
             \ IS_ABSOLUTE
             \ IS_DIRECTORY
+            \ IS_EXECUTABLE
             \ IS_NEWER_THAN
+            \ IS_READABLE
             \ IS_SYMLINK
+            \ IS_WRITABLE
             \ LESS
             \ LESS_EQUAL
             \ MATCHES
             \ NNNN
             \ NOT
             \ OFF
-            \ OR
             \ PATH_EQUAL
             \ POLICY
             \ STREQUAL
@@ -3708,15 +4139,14 @@
             \ __CURRENT_FILE_VAR__
 
 syn keyword cmakeKWinstall contained
-            \ AFTER
-            \ AIX
             \ ALL_COMPONENTS
+            \ APPENDIX
             \ APT
             \ ARCHIVE
-            \ BEFORE
             \ BUILD_TYPE
-            \ BUNDLE
             \ BUNDLE_EXECUTABLE
+            \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES
+            \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO
             \ CMAKE_INSTALL_BINDIR
             \ CMAKE_INSTALL_DATADIR
             \ CMAKE_INSTALL_DATAROOTDIR
@@ -3724,6 +4154,7 @@
             \ CMAKE_INSTALL_INCLUDEDIR
             \ CMAKE_INSTALL_INFODIR
             \ CMAKE_INSTALL_LIBDIR
+            \ CMAKE_INSTALL_LIBEXECDIR
             \ CMAKE_INSTALL_LOCALEDIR
             \ CMAKE_INSTALL_LOCALSTATEDIR
             \ CMAKE_INSTALL_MANDIR
@@ -3732,9 +4163,12 @@
             \ CMAKE_INSTALL_SBINDIR
             \ CMAKE_INSTALL_SHARESTATEDIR
             \ CMAKE_INSTALL_SYSCONFDIR
+            \ CMAKE_MAP_IMPORTED_CONFIG_
             \ CODE
+            \ COMPAT_VERSION
             \ COMPONENT
             \ CONFIGURATIONS
+            \ CPS
             \ CVS
             \ CXX_MODULES_BMI
             \ CXX_MODULES_DIRECTORY
@@ -3742,19 +4176,28 @@
             \ DATAROOT
             \ DBUILD_TYPE
             \ DCOMPONENT
+            \ DEFAULT_CONFIGURATIONS
+            \ DEFAULT_LICENSE
+            \ DEFAULT_TARGETS
+            \ DESCRIPTION
             \ DESTDIR
             \ DESTINATION
             \ DIRECTORY
             \ DIRECTORY_PERMISSIONS
             \ DLL
             \ DOC
+            \ ENABLED
             \ ENABLE_EXPORTS
+            \ EXCLUDE_EMPTY_DIRECTORIES
             \ EXCLUDE_FROM_ALL
             \ EXECUTABLES
             \ EXPORT
             \ EXPORT_ANDROID_MK
+            \ EXPORT_FIND_PACKAGE_NAME
             \ EXPORT_LINK_INTERFACE_LIBRARIES
             \ EXPORT_NAME
+            \ EXPORT_PACKAGE_DEPENDENCIES
+            \ EXTRA_ARGS
             \ FILES
             \ FILES_MATCHING
             \ FILE_PERMISSIONS
@@ -3765,15 +4208,19 @@
             \ GROUP_READ
             \ GROUP_WRITE
             \ HEADERS
+            \ HOMEPAGE_URL
             \ IMPORTED_RUNTIME_ARTIFACTS
             \ INCLUDES
-            \ INFO
+            \ INSTALL_PARALLEL
             \ INSTALL_PREFIX
             \ INTERFACE
             \ INTERFACE_INCLUDE_DIRECTORIES
+            \ LIBEXEC
             \ LIBRARY
+            \ LICENSE
             \ LOCALE
             \ LOCALSTATE
+            \ LOWER_CASE_FILE
             \ MACOSX_BUNDLE
             \ MAN
             \ MESSAGE_NEVER
@@ -3782,11 +4229,14 @@
             \ NAMELINK_SKIP
             \ NAMESPACE
             \ NDK
+            \ NO_PROJECT_METADATA
             \ OBJECTS
+            \ OFF
             \ OPTIONAL
             \ OWNER_EXECUTE
             \ OWNER_READ
             \ OWNER_WRITE
+            \ PACKAGE_INFO
             \ PATTERN
             \ PERMISSIONS
             \ POST_EXCLUDE_FILES
@@ -3799,9 +4249,12 @@
             \ PRE_INSTALL_SCRIPT
             \ PRIVATE_HEADER
             \ PROGRAMS
+            \ PROJECT
             \ PROPERTIES
+            \ PROPERTY
             \ PUBLIC_HEADER
             \ RENAME
+            \ REQUIRED
             \ RESOURCE
             \ RPM
             \ RUNSTATE
@@ -3811,8 +4264,11 @@
             \ SCRIPT
             \ SETGID
             \ SETUID
+            \ SETUP
             \ SHAREDSTATE
             \ SOVERSION
+            \ SPDX
+            \ SPDX_LICENSE
             \ STATIC
             \ SYSCONF
             \ TARGETS
@@ -3820,6 +4276,7 @@
             \ TYPE
             \ USE_SOURCE_PERMISSIONS
             \ VERSION
+            \ VERSION_SCHEMA
             \ WORLD_EXECUTE
             \ WORLD_READ
             \ WORLD_WRITE
@@ -3896,7 +4353,9 @@
 syn keyword cmakeKWload_cache contained
             \ EXCLUDE
             \ INCLUDE_INTERNALS
+            \ OTHER_PROJECT_INTERNAL_CACHE_VAR
             \ READ_WITH_PREFIX
+            \ STATUS
 
 syn keyword cmakeKWload_command contained
             \ CMAKE_LOADED_COMMAND_
@@ -3955,7 +4414,10 @@
             \ ASM_MASM
             \ ASM_NASM
             \ ATT
+            \ CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO
             \ CMAKE_PROJECT_
+            \ COMPAT_VERSION
+            \ CPS
             \ CUDA
             \ DESCRIPTION
             \ HIP
@@ -3967,14 +4429,16 @@
             \ OBJC
             \ OBJCXX
             \ PROJECT
+            \ SPDX_LICENSE
             \ VERSION
             \ _BINARY_DIR
+            \ _COMPAT_VERSION
             \ _DESCRIPTION
             \ _HOMEPAGE_URL
             \ _INCLUDE_BEFORE
             \ _IS_TOP_LEVEL
             \ _SOURCE_DIR
-            \ _VERSION
+            \ _SPDX_LICENSE
             \ _VERSION_MAJOR
             \ _VERSION_MINOR
             \ _VERSION_PATCH
@@ -4051,6 +4515,7 @@
             \ PROPERTIES
 
 syn keyword cmakeKWset_tests_properties contained
+            \ DIRECTORY
             \ NAME
             \ PROPERTIES
 
@@ -4195,28 +4660,35 @@
 
 syn keyword cmakeKWtarget_link_libraries contained
             \ ALIAS
+            \ CMAKE_
             \ DA
             \ DAG
             \ DEBUG_CONFIGURATIONS
             \ DOBJ
+            \ GCC
             \ IMPORTED
+            \ IMPORTED_CONFIGURATIONS
             \ IMPORTED_NO_SONAME
             \ INTERFACE
             \ INTERFACE_LINK_LIBRARIES
+            \ LANG
+            \ LINKER
             \ LINK_FLAGS
             \ LINK_INTERFACE_LIBRARIES
-            \ LINK_INTERFACE_LIBRARIES_DEBUG
             \ LINK_INTERFACE_MULTIPLICITY
+            \ LINK_LIBRARIES_STRATEGY
             \ LINK_OPTIONS
             \ LINK_PRIVATE
             \ LINK_PUBLIC
             \ OBJECT
-            \ OLD
             \ PRIVATE
             \ PUBLIC
             \ SHARED
+            \ SHELL
             \ STATIC
             \ TARGET_OBJECTS
+            \ _LINKER_WRAPPER_FLAG
+            \ _LINKER_WRAPPER_FLAG_SEP
 
 syn keyword cmakeKWtarget_link_options contained
             \ ALIAS
@@ -4250,7 +4722,6 @@
             \ BUILD_INTERFACE
             \ COMPILE_LANGUAGE
             \ DISABLE_PRECOMPILE_HEADERS
-            \ EXPORT
             \ FI
             \ GCC
             \ IMPORTED
@@ -4312,27 +4783,29 @@
             \ CUDA_STANDARD
             \ CUDA_STANDARD_REQUIRED
             \ CXX_EXTENSIONS
+            \ CXX_MODULE
+            \ CXX_MODULES
             \ CXX_STANDARD
             \ CXX_STANDARD_REQUIRED
             \ C_EXTENSIONS
             \ C_STANDARD
             \ C_STANDARD_REQUIRED
+            \ DCOMPILE_DEFINITIONS
             \ DEFINED
             \ DLINK_LIBRARIES
             \ DVAR
             \ EXECUTABLE
             \ FALSE
+            \ FILE_SET
             \ GHS
-            \ HIP_EXTENSIONS
-            \ HIP_STANDARD
-            \ HIP_STANDARD_REQUIRED
             \ INCLUDE_DIRECTORIES
-            \ LANG
+            \ LINKER_LANGUAGE
             \ LINK_DIRECTORIES
             \ LINK_LIBRARIES
             \ LINK_OPTIONS
             \ LOG_DESCRIPTION
             \ MULTI
+            \ NORMAL
             \ NOT
             \ NO_CACHE
             \ NO_LOG
@@ -4345,8 +4818,9 @@
             \ OUTPUT_VARIABLE
             \ PRIVATE
             \ PROJECT
+            \ PROPAGATE_TOP_LEVEL_INCLUDES_TO_TRY_COMPILE
             \ RESULTVAR
-            \ SOURCES
+            \ SOURCES_TYPE
             \ SOURCE_DIR
             \ SOURCE_FROM_CONTENT
             \ SOURCE_FROM_FILE
@@ -4355,7 +4829,6 @@
             \ STATIC_LIBRARY_OPTIONS
             \ TARGET
             \ TRUE
-            \ TYPE
             \ VALUE
             \ _EXTENSIONS
             \ _STANDARD
@@ -4369,8 +4842,8 @@
             \ COPY_FILE
             \ COPY_FILE_ERROR
             \ FAILED_TO_RUN
-            \ FALSE
             \ LANG
+            \ LINKER_LANGUAGE
             \ LINK_LIBRARIES
             \ LINK_OPTIONS
             \ LOG_DESCRIPTION
@@ -4379,11 +4852,10 @@
             \ RUN_OUTPUT_STDERR_VARIABLE
             \ RUN_OUTPUT_STDOUT_VARIABLE
             \ RUN_OUTPUT_VARIABLE
-            \ SOURCES
+            \ SOURCES_TYPE
             \ SOURCE_FROM_CONTENT
             \ SOURCE_FROM_FILE
             \ SOURCE_FROM_VAR
-            \ TRUE
             \ WORKING_DIRECTORY
             \ _EXTENSIONS
             \ _STANDARD
@@ -4423,7 +4895,6 @@
 syn keyword cmakeGeneratorExpressions contained
             \ ABSOLUTE_PATH
             \ ACTION
-            \ AIX
             \ ANGLE
             \ APPEND
             \ ARCHIVE_OUTPUT_NAME
@@ -4440,6 +4911,7 @@
             \ COMMAND_CONFIG
             \ COMMAND_EXPAND_LISTS
             \ COMPARE
+            \ COMPATIBLE_INTERFACE_
             \ COMPILE_DEFINITIONS
             \ COMPILE_FEATURES
             \ COMPILE_LANGUAGE
@@ -4453,16 +4925,25 @@
             \ CONFIG
             \ CONFIGURATION
             \ CONTENT
+            \ CUDA_COMPILER_FRONTEND_VARIANT
             \ CUDA_COMPILER_ID
+            \ CUDA_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CUDA_COMPILER_LINKER_ID
             \ CUDA_COMPILER_VERSION
             \ CUDA_RESOLVE_DEVICE_SYMBOLS
             \ CUDA_SEPARABLE_COMPILATION
             \ CUSTOM_KEYS
+            \ CXX_COMPILER_FRONTEND_VARIANT
             \ CXX_COMPILER_ID
+            \ CXX_COMPILER_LINKER_FRONTEND_VARIANT
+            \ CXX_COMPILER_LINKER_ID
             \ CXX_COMPILER_VERSION
             \ CXX_CONFIG
             \ CXX_STANDARD
+            \ C_COMPILER_FRONTEND_VARIANT
             \ C_COMPILER_ID
+            \ C_COMPILER_LINKER_FRONTEND_VARIANT
+            \ C_COMPILER_LINKER_ID
             \ C_COMPILER_VERSION
             \ C_STANDARD
             \ DEBUG_MODE
@@ -4501,9 +4982,11 @@
             \ HAS_ROOT_PATH
             \ HAS_STEM
             \ HAVE_SOME_FEATURE
+            \ HIP_COMPILER_FRONTEND_VARIANT
             \ HIP_COMPILER_ID
+            \ HIP_COMPILER_LINKER_FRONTEND_VARIANT
+            \ HIP_COMPILER_LINKER_ID
             \ HIP_COMPILER_VERSION
-            \ HIP_STANDARD
             \ HOST_LINK
             \ IF
             \ IGNORE
@@ -4519,7 +5002,9 @@
             \ INSTALL_RPATH
             \ INTERFACE_LINK_LIBRARIES
             \ INTERFACE_LINK_LIBRARIES_DIRECT
+            \ INTERFACE_PROP
             \ IN_LIST
+            \ ISPC_COMPILER_FRONTEND_VARIANT
             \ ISPC_COMPILER_ID
             \ ISPC_COMPILER_VERSION
             \ IS_ABSOLUTE
@@ -4546,14 +5031,21 @@
             \ MAKE_C_IDENTIFIER
             \ MAP_IMPORTED_CONFIG_
             \ MODULE
+            \ NATIVE_PATH
             \ NATURAL
             \ NO
             \ NORMALIZE
             \ NORMAL_PATH
             \ NOT
+            \ OBJCXX_COMPILER_FRONTEND_VARIANT
             \ OBJCXX_COMPILER_ID
+            \ OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT
+            \ OBJCXX_COMPILER_LINKER_ID
             \ OBJCXX_COMPILER_VERSION
+            \ OBJC_COMPILER_FRONTEND_VARIANT
             \ OBJC_COMPILER_ID
+            \ OBJC_COMPILER_LINKER_FRONTEND_VARIANT
+            \ OBJC_COMPILER_LINKER_ID
             \ OBJC_COMPILER_VERSION
             \ OBJECT
             \ OFF
@@ -4577,6 +5069,7 @@
             \ PREPEND
             \ PRIVATE
             \ PUBLIC
+            \ QUOTE
             \ REGEX
             \ RELATIVE_PATH
             \ REMOVE_AT
@@ -4665,6 +5158,8 @@
             \ TRANSFORM_REPLACE
             \ TRANSFORM_STRIP
             \ TRANSFORM_TOLOWER
+            \ TRANSITIVE_COMPILE_PROPERTIES
+            \ TRANSITIVE_LINK_PROPERTIES
             \ UNKNOWN
             \ UPPER_CASE
             \ VERBATIM
@@ -4674,6 +5169,9 @@
             \ VERSION_LESS_EQUAL
             \ WHOLE_ARCHIVE
             \ WRONG
+            \ _COMPILER_FRONTEND_VARIANT
+            \ _COMPILER_LINKER_FRONTEND_VARIANT
+            \ _COMPILER_LINKER_ID
             \ _LINK_GROUP_USING_
             \ _LINK_LIBRARY_USING_
             \ _POSTFIX
@@ -4694,15 +5192,16 @@
             \ add_subdirectory
             \ add_test
             \ aux_source_directory
-            \ block
             \ break
             \ build_command
             \ cmake_file_api
             \ cmake_host_system_information
+            \ cmake_instrumentation
             \ cmake_language
             \ cmake_minimum_required
             \ cmake_parse_arguments
             \ cmake_path
+            \ cmake_pkg_config
             \ cmake_policy
             \ configure_file
             \ continue
@@ -4723,9 +5222,6 @@
             \ define_property
             \ enable_language
             \ enable_testing
-            \ endblock
-            \ endfunction
-            \ endmacro
             \ execute_process
             \ export
             \ file
@@ -4735,7 +5231,6 @@
             \ find_path
             \ find_program
             \ fltk_wrap_ui
-            \ function
             \ get_cmake_property
             \ get_directory_property
             \ get_filename_component
@@ -4753,7 +5248,6 @@
             \ list
             \ load_cache
             \ load_command
-            \ macro
             \ mark_as_advanced
             \ math
             \ message
@@ -4788,20 +5282,6 @@
             \ variable_watch
             \ nextgroup=cmakeArguments
 
-syn keyword cmakeCommandConditional
-            \ else
-            \ elseif
-            \ endif
-            \ if
-            \ nextgroup=cmakeArguments
-
-syn keyword cmakeCommandRepeat
-            \ endforeach
-            \ endwhile
-            \ foreach
-            \ while
-            \ nextgroup=cmakeArguments
-
 syn keyword cmakeCommandDeprecated
             \ build_name
             \ exec_program
@@ -4830,14 +5310,14 @@
 hi def link cmakeBracketArgument String
 hi def link cmakeBracketComment Comment
 hi def link cmakeCommand Function
-hi def link cmakeCommandConditional Conditional
 hi def link cmakeCommandDeprecated WarningMsg
-hi def link cmakeCommandRepeat Repeat
 hi def link cmakeComment Comment
+hi def link cmakeElse Conditional
 hi def link cmakeEnvironment Special
 hi def link cmakeEscaped Special
 hi def link cmakeGeneratorExpression WarningMsg
 hi def link cmakeGeneratorExpressions Constant
+hi def link cmakeKeyword Conditional
 hi def link cmakeModule Include
 hi def link cmakeProperty Constant
 hi def link cmakeRegistry Underlined
@@ -4863,10 +5343,12 @@
 hi def link cmakeKWbuild_command ModeMsg
 hi def link cmakeKWcmake_file_api ModeMsg
 hi def link cmakeKWcmake_host_system_information ModeMsg
+hi def link cmakeKWcmake_instrumentation ModeMsg
 hi def link cmakeKWcmake_language ModeMsg
 hi def link cmakeKWcmake_minimum_required ModeMsg
 hi def link cmakeKWcmake_parse_arguments ModeMsg
 hi def link cmakeKWcmake_path ModeMsg
+hi def link cmakeKWcmake_pkg_config ModeMsg
 hi def link cmakeKWcmake_policy ModeMsg
 hi def link cmakeKWconfigure_file ModeMsg
 hi def link cmakeKWcreate_test_sourcelist ModeMsg
@@ -4883,7 +5365,6 @@
 hi def link cmakeKWdefine_property ModeMsg
 hi def link cmakeKWdoxygen_add_docs ModeMsg
 hi def link cmakeKWenable_language ModeMsg
-hi def link cmakeKWenable_testing ModeMsg
 hi def link cmakeKWexec_program ModeMsg
 hi def link cmakeKWexecute_process ModeMsg
 hi def link cmakeKWexport ModeMsg
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cab0fcb..42903e8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file LICENSE.rst or https://cmake.org/licensing for details.
 
-cmake_minimum_required(VERSION 3.13...3.31 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...4.0 FATAL_ERROR)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake)
 set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake)
 
@@ -492,13 +492,21 @@
         NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC") OR
        CMAKE_C_COMPILER_ID STREQUAL "AppleClang" OR
        CMAKE_C_COMPILER_ID STREQUAL "LCC")
-      set(C_FLAGS_LIST -Wcast-align -Werror-implicit-function-declaration -Wchar-subscripts
+      set(C_FLAGS_LIST -Wcast-align -Wchar-subscripts
                        -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security
                        -Wmissing-format-attribute -fno-common -Wundef
+                       -Werror=implicit-function-declaration
+                       -Wstrict-prototypes
       )
       set(CXX_FLAGS_LIST -Wnon-virtual-dtor -Wcast-align -Wchar-subscripts -Wall -W
                          -Wshadow -Wpointer-arith -Wformat-security -Wundef
       )
+      if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND
+          NOT (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11))
+        list(APPEND CXX_FLAGS_LIST
+          -Wundefined-func-template
+        )
+      endif()
 
       foreach(FLAG_LANG IN ITEMS C CXX)
         foreach(FLAG IN LISTS ${FLAG_LANG}_FLAGS_LIST)
diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst
index 31565b5..8d66752 100644
--- a/Help/command/add_custom_command.rst
+++ b/Help/command/add_custom_command.rst
@@ -357,6 +357,7 @@
   Execute the command with the given current working directory.
   If it is a relative path, it will be interpreted relative to the
   build tree directory corresponding to the current source directory.
+  If not specified, set to :variable:`CMAKE_CURRENT_BINARY_DIR`.
 
   This option is currently ignored if ``APPEND`` is given, but a future
   version may use it.
diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst
index b574cba..83fe6b4 100644
--- a/Help/command/add_custom_target.rst
+++ b/Help/command/add_custom_target.rst
@@ -191,6 +191,7 @@
   Execute the command with the given current working directory.
   If it is a relative path it will be interpreted relative to the
   build tree directory corresponding to the current source directory.
+  If not specified, set to :variable:`CMAKE_CURRENT_BINARY_DIR`.
 
   .. versionadded:: 3.13
     Arguments to ``WORKING_DIRECTORY`` may use
diff --git a/Help/command/add_test.rst b/Help/command/add_test.rst
index dbaa4fb..bbfcca2 100644
--- a/Help/command/add_test.rst
+++ b/Help/command/add_test.rst
@@ -114,4 +114,5 @@
 Unlike the above ``NAME`` signature, target names are not supported
 in the command-line.  Furthermore, tests added with this signature do not
 support :manual:`generator expressions <cmake-generator-expressions(7)>`
-in the command-line or test properties.
+in the command-line or test properties, and the :prop_tgt:`TEST_LAUNCHER`
+and :prop_tgt:`CROSSCOMPILING_EMULATOR` target properties are not supported.
diff --git a/Help/command/cmake_instrumentation.rst b/Help/command/cmake_instrumentation.rst
index 22e77ea..519decf 100644
--- a/Help/command/cmake_instrumentation.rst
+++ b/Help/command/cmake_instrumentation.rst
@@ -19,7 +19,7 @@
     API_VERSION <version>
     DATA_VERSION <version>
     [HOOKS <hooks>...]
-    [QUERIES <queries>...]
+    [OPTIONS <options>...]
     [CALLBACK <callback>]
   )
 
@@ -28,7 +28,7 @@
 for details of the ``API_VERSION`` and :ref:`cmake-instrumentation Data v1` for details
 of the ``DATA_VERSION``.
 
-Each of the optional keywords ``HOOKS``, ``QUERIES``, and ``CALLBACK``
+Each of the optional keywords ``HOOKS``, ``OPTIONS``, and ``CALLBACK``
 correspond to one of the parameters to the :ref:`cmake-instrumentation v1 Query Files`.
 The ``CALLBACK`` keyword can be provided multiple times to create multiple callbacks.
 
@@ -48,7 +48,7 @@
     API_VERSION 1
     DATA_VERSION 1
     HOOKS postGenerate preCMakeBuild postCMakeBuild
-    QUERIES staticSystemInformation dynamicSystemInformation
+    OPTIONS staticSystemInformation dynamicSystemInformation
     CALLBACK ${CMAKE_COMMAND} -P /path/to/handle_data.cmake
     CALLBACK ${CMAKE_COMMAND} -P /path/to/handle_data_2.cmake
   )
@@ -60,7 +60,7 @@
     "hooks": [
       "postGenerate", "preCMakeBuild", "postCMakeBuild"
     ],
-    "queries": [
+    "options": [
       "staticSystemInformation", "dynamicSystemInformation"
     ],
     "callbacks": [
diff --git a/Help/command/execute_process.rst b/Help/command/execute_process.rst
index a2f9036..37f2b42 100644
--- a/Help/command/execute_process.rst
+++ b/Help/command/execute_process.rst
@@ -75,7 +75,8 @@
 
 ``WORKING_DIRECTORY``
  The named directory will be set as the current working directory of
- the child processes.
+ the child processes. If not given, the child processes' working directory is
+ unspecified.
 
 ``TIMEOUT``
  After the specified number of seconds (fractions allowed), all unfinished
diff --git a/Help/command/export.rst b/Help/command/export.rst
index 6668e97..9673869 100644
--- a/Help/command/export.rst
+++ b/Help/command/export.rst
@@ -141,7 +141,9 @@
           [VERSION_SCHEMA <string>]]
          [DEFAULT_TARGETS <target>...]
          [DEFAULT_CONFIGURATIONS <config>...]
-         [DESCRIPTION <project-description-string>]
+         [LICENSE <license-string>]
+         [DEFAULT_LICENSE <license-string>]
+         [DESCRIPTION <description-string>]
          [HOMEPAGE_URL <url-string>])
 
 .. versionadded:: 4.1
diff --git a/Help/command/find_file.rst b/Help/command/find_file.rst
index 9695ddf..a1dc5f9 100644
--- a/Help/command/find_file.rst
+++ b/Help/command/find_file.rst
@@ -4,7 +4,7 @@
 .. |FIND_XXX| replace:: find_file
 .. |NAMES| replace:: NAMES name1 [name2 ...]
 .. |SEARCH_XXX| replace:: full path to a file
-.. |SEARCH_XXX_DESC| replace:: full path to named file
+.. |SEARCH_XXX_DESC| replace:: full path to a named file
 .. |prefix_XXX_SUBDIR| replace:: ``<prefix>/include``
 .. |entry_XXX_SUBDIR| replace:: ``<entry>/include``
 
diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst
index 4dc9696..a3ceef2 100644
--- a/Help/command/find_package.rst
+++ b/Help/command/find_package.rst
@@ -141,7 +141,8 @@
                [REGISTRY_VIEW  (64|32|64_32|32_64|HOST|TARGET|BOTH)]
                [GLOBAL]
                [NO_POLICY_SCOPE]
-               [BYPASS_PROVIDER])
+               [BYPASS_PROVIDER]
+               [UNWIND_INCLUDE])
 
 The basic signature is supported by both Module and Config modes.
 The ``MODULE`` keyword implies that only Module mode can be used to find
@@ -249,6 +250,21 @@
   itself.  Future versions of CMake may detect attempts to use this keyword
   from places other than a dependency provider and halt with a fatal error.
 
+.. versionadded:: 4.2
+  The ``UNWIND_INCLUDE`` keyword is only allowed when ``find_package()`` is
+  being called within a parent call to ``find_package()``. When a call to
+  ``find_package(UNWIND_INCLUDE)`` fails to find the desired package, it begins
+  an "unwind" state. In this state further calls to ``find_package()`` and
+  :command:`include()` are forbidden, and all parent :command:`include()`
+  commands will immediately invoke :command:`return()` when their scope is
+  reached. This "unwinding" will continue until the parent ``find_package()``
+  is returned to.
+
+  ``UNWIND_INCLUDE`` is only intended to be used by calls to ``find_package()``
+  generated by :command:`install(EXPORT_PACKAGE_DEPENDENCIES)`, but may be
+  useful to those who wish to manually manage their dependencies in a similar
+  manner.
+
 .. _`full signature`:
 
 Full Signature
@@ -581,12 +597,12 @@
 configuration file found is used, even if a newer version of the package
 resides later in the list of search paths.
 
-For search paths which contain glob expressions (``*``), the order in which
-directories matching the glob are searched is unspecified unless the
-:variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` variable is set.  This variable,
-along with the :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable,
-determines the order in which CMake considers glob matches.  For example, if
-the file system contains the package configuration files
+For search paths which contain glob expressions (``*``), directories matching
+the glob are searched in natural, descending order by default. This behavior
+can be overridden by setting variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`
+and :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` accordingly. Those variables
+determine the order in which CMake considers glob matches. For example, if the
+file system contains the package configuration files
 
 ::
 
@@ -594,21 +610,21 @@
   <prefix>/example-1.10/example-config.cmake
   <prefix>/share/example-2.0/example-config.cmake
 
-it is unspecified (when the aforementioned variables are unset) whether
-``find_package(example)`` will find ``example-1.2`` or ``example-1.10``
-(assuming that both are viable), but ``find_package`` will *not* find
-``example-2.0``, because one of the other two will be found first.
+then ``find_package(example)`` will (when the aforementioned variables are
+unset) pick ``example-1.10`` (assuming both ``example-1.2`` and ``example-1.10``
+are viable). Note however that ``find_package`` will *not* find ``example-2.0``,
+because one of the other two will be found first.
 
 To control the order in which ``find_package`` searches directories that match
 a glob expression, use :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` and
 :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`.
-For instance, to cause the above example to select ``example-1.10``,
+For instance, to cause the above example to select ``example-1.2``,
 one can set
 
 .. code-block:: cmake
 
   set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
-  set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+  set(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
 
 before calling ``find_package``.
 
@@ -624,6 +640,15 @@
    and ``<prefix>/<name>.framework/Versions/*/Resources/CMake``.  In previous
    versions of CMake, this order was unspecified.
 
+.. versionchanged:: 4.2
+   When encountering multiple viable matches, ``find_package`` now picks the
+   one with the most recent version by default. In previous versions of CMake,
+   the result was unspecified. Accordingly, the default of
+   :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` has changed from ``NONE`` to
+   ``NATURAL`` and :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`
+   now defaults to ``DEC`` (descending) instead of ``ASC`` (ascending).
+
+
 .. include:: include/FIND_XXX_ROOT.rst
 .. include:: include/FIND_XXX_ORDER.rst
 
diff --git a/Help/command/include/FIND_XXX.rst b/Help/command/include/FIND_XXX.rst
index 9d063ad..194b6f8 100644
--- a/Help/command/include/FIND_XXX.rst
+++ b/Help/command/include/FIND_XXX.rst
@@ -32,11 +32,27 @@
             )
 
 This command is used to find a |SEARCH_XXX_DESC|.
-A cache entry, or a normal variable if ``NO_CACHE`` is specified,
-named by ``<VAR>`` is created to store the result of this command.
-If the |SEARCH_XXX| is found the result is stored in the variable
-and the search will not be repeated unless the variable is cleared.
-If nothing is found, the result will be ``<VAR>-NOTFOUND``.
+
+Prior to searching, |FIND_XXX| checks if variable ``<VAR>`` is defined. If
+the variable is not defined, the search will be performed. If the variable is
+defined and its value is ``NOTFOUND``, or ends in ``-NOTFOUND``, the search
+will be performed. If the variable contains any other value the search is not
+performed.
+
+  .. note::
+      ``VAR`` is considered defined if it is available in the current scope. See
+      the :ref:`cmake-language(7) variables <CMake Language Variables>`
+      documentation for details on scopes, and the interaction of normal
+      variables and cache entries.
+
+The results of the search will be stored in a cache entry named ``<VAR>``.
+Future calls to |FIND_XXX| will inspect this cache entry when specifying the
+same ``<VAR>``. This optimization ensures successful searches will not be
+repeated unless the cache entry is :command:`unset`.
+
+If the |SEARCH_XXX| is found the recorded value in cache entry ``<VAR>`` will
+be the result of the search. If nothing is found, the recorded value will be
+``<VAR>-NOTFOUND``.
 
 Options include:
 
@@ -103,8 +119,9 @@
 
   .. note::
 
-    If the variable is already set before the call (as a normal or cache
-    variable) then the search will not occur.
+    |FIND_XXX| will still check for ``<VAR>`` as usual, checking first for a
+    variable, and then a cache entry. If either indicate a previous successful
+    search, the search will not be performed.
 
   .. warning::
 
diff --git a/Help/command/install.rst b/Help/command/install.rst
index 033c5c6..f3c4d2f 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -993,7 +993,9 @@
              [VERSION_SCHEMA <string>]]
             [DEFAULT_TARGETS <target>...]
             [DEFAULT_CONFIGURATIONS <config>...]
-            [DESCRIPTION <project-description-string>]
+            [LICENSE <license-string>]
+            [DEFAULT_LICENSE <license-string>]
+            [DESCRIPTION <description-string>]
             [HOMEPAGE_URL <url-string>]
             [PERMISSIONS <permission>...]
             [CONFIGURATIONS <config>...]
@@ -1051,7 +1053,25 @@
     configurations exists.  If not specified, CMake will fall back to the
     package's available configurations in an unspecified order.
 
-  ``DESCRIPTION <project-description-string>``
+  ``LICENSE <license-string>``
+    .. versionadded:: 4.2
+
+    A |SPDX|_ (SPDX) `License Expression`_ that describes the license(s) of the
+    project as a whole, including documentation, resources, or other materials
+    distributed with the project, in addition to software artifacts.  See the
+    SPDX `License List`_ for a list of commonly used licenses and their
+    identifiers.
+
+    The license of individual components is taken from the
+    :prop_tgt:`SPDX_LICENSE` property of their respective targets.
+
+  ``DEFAULT_LICENSE <license-string>``
+    .. versionadded:: 4.2
+
+    A |SPDX|_ (SPDX) `License Expression`_ that describes the license(s) of any
+    components which do not otherwise specify their license(s).
+
+  ``DESCRIPTION <description-string>``
     .. versionadded:: 4.1
 
     An informational description of the project.  It is recommended that this
@@ -1283,3 +1303,9 @@
 
 .. _cps-version_schema: https://cps-org.github.io/cps/schema.html#version-schema
 .. |cps-version_schema| replace:: ``version_schema``
+
+.. _SPDX: https://spdx.dev/
+.. |SPDX| replace:: System Package Data Exchange
+
+.. _License Expression: https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/
+.. _License List: https://spdx.org/licenses/
diff --git a/Help/command/project.rst b/Help/command/project.rst
index bf0f171..a079bab 100644
--- a/Help/command/project.rst
+++ b/Help/command/project.rst
@@ -12,7 +12,8 @@
  project(<PROJECT-NAME>
          [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
          [COMPAT_VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
-         [DESCRIPTION <project-description-string>]
+         [SPDX_LICENSE <license-string>]
+         [DESCRIPTION <description-string>]
          [HOMEPAGE_URL <url-string>]
          [LANGUAGES <language-name>...])
 
@@ -106,7 +107,30 @@
     ``CMakeLists.txt``, then the compatibility version is also stored in the
     variable :variable:`CMAKE_PROJECT_COMPAT_VERSION`.
 
-``DESCRIPTION <project-description-string>``
+``SPDX_LICENSE <license-string>``
+  .. versionadded:: 4.2
+
+  Optional.
+  Sets the variables
+
+  * :variable:`PROJECT_SPDX_LICENSE`,
+    :variable:`<PROJECT-NAME>_SPDX_LICENSE`
+
+  to ``<license-string>``, which shall be a |SPDX|_ (SPDX)
+  `License Expression`_ that describes the license(s) of the project as a
+  whole, including documentation, resources, or other materials distributed
+  with the project, in addition to software artifacts. See the SPDX
+  `License List`_ for a list of commonly used licenses and their identifiers.
+  See the :prop_tgt:`SPDX_LICENSE` property for specifying the license(s) on
+  individual software artifacts.
+
+.. _SPDX: https://spdx.dev/
+.. |SPDX| replace:: System Package Data Exchange
+
+.. _License Expression: https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/
+.. _License List: https://spdx.org/licenses/
+
+``DESCRIPTION <description-string>``
   .. versionadded:: 3.9
 
   Optional.
@@ -114,7 +138,7 @@
 
   * :variable:`PROJECT_DESCRIPTION`, :variable:`<PROJECT-NAME>_DESCRIPTION`
 
-  to ``<project-description-string>``.
+  to ``<description-string>``.
   It is recommended that this description is a relatively short string,
   usually no more than a few words.
 
@@ -149,10 +173,11 @@
 Specify language ``NONE``, or use the ``LANGUAGES`` keyword and list no languages,
 to skip enabling any languages.
 
-The variables set through the ``VERSION``, ``COMPAT_VERSION``, ``DESCRIPTION``
-and ``HOMEPAGE_URL`` options are intended for use as default values in package
-metadata and documentation. The :command:`export` and :command:`install`
-commands use these accordingly when generating |CPS| package descriptions.
+The variables set through the ``VERSION``, ``COMPAT_VERSION``,
+``SPDX_LICENSE``, ``DESCRIPTION`` and ``HOMEPAGE_URL`` options are
+intended for use as default values in package metadata and documentation.
+The :command:`export` and :command:`install` commands use these accordingly
+when generating |CPS| package descriptions.
 
 .. |CPS| replace:: Common Package Specification
 
diff --git a/Help/command/set.rst b/Help/command/set.rst
index 6c1af47..12413f9 100644
--- a/Help/command/set.rst
+++ b/Help/command/set.rst
@@ -44,15 +44,16 @@
 ^^^^^^^^^^^^^^^
 
 .. signature::
-  set(<variable> <value>... CACHE <type> <docstring> [FORCE])
+  set(CACHE{<variable>} [TYPE <type>] [HELP <helpstring>...] [FORCE]
+                        VALUE [<value>...])
   :target: CACHE
 
-  Sets the given cache ``<variable>`` (cache entry).  Since cache entries
-  are meant to provide user-settable values this does not overwrite
-  existing cache entries by default.  Use the ``FORCE`` option to
-  overwrite existing entries.
+  .. versionadded:: 4.2
 
-  The ``<type>`` must be specified as one of:
+  Sets the given cache ``<variable>`` (cache entry). The options are:
+
+  ``TYPE <type>``
+    Specify the type of the cache entry. The ``<type>`` must be one of:
 
     ``BOOL``
       Boolean ``ON/OFF`` value.
@@ -77,9 +78,26 @@
       They may be used to store variables persistently across runs.
       Use of this type implies ``FORCE``.
 
-  The ``<docstring>`` must be specified as a line of text
-  providing a quick summary of the option
-  for presentation to :manual:`cmake-gui(1)` users.
+    If ``TYPE`` is not specified, if the cache variable already exist and its
+    type is not ``UNINITIALIZED``, the type previously specified will be kept
+    otherwise, ``STRING`` will be used.
+
+  ``HELP <helpstring>...``
+    The ``<helpstring>`` must be specified as a line of text providing a quick
+    summary of the option for presentation to :manual:`cmake-gui(1)` users. If
+    more than one string is given, they are concatenated into a single string
+    with no separator between them.
+
+    If ``HELP`` is not specified, an empty string will be used.
+
+  ``FORCE``
+    Since cache entries are meant to provide user-settable values this does not
+    overwrite existing cache entries by default.  Use the ``FORCE`` option to
+    overwrite existing entries.
+
+  ``VALUE <value>...``
+    List of values to be set to the cache ``<variable>``. This argument must be
+    always the last one.
 
   If the cache entry does not exist prior to the call or the ``FORCE``
   option is given then the cache entry will be set to the given value.
@@ -101,6 +119,13 @@
   then the ``set`` command will treat the path as relative to the
   current working directory and convert it to an absolute path.
 
+.. signature::
+  set(<variable> <value>... CACHE <type> <docstring> [FORCE])
+  :target: CACHE_legacy
+
+  This signature is supported for compatibility purpose. Use preferably the
+  other one.
+
 Set Environment Variable
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/Help/command/unset.rst b/Help/command/unset.rst
index f78d01f..8512246 100644
--- a/Help/command/unset.rst
+++ b/Help/command/unset.rst
@@ -3,37 +3,54 @@
 
 Unset a variable, cache variable, or environment variable.
 
-Unset Normal Variable or Cache Entry
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Unset Normal Variable
+^^^^^^^^^^^^^^^^^^^^^
 
-.. code-block:: cmake
+.. signature::
+  unset(<variable> [PARENT_SCOPE])
+  :target: normal
 
-  unset(<variable> [CACHE | PARENT_SCOPE])
+  Removes a normal variable from the current scope, causing it
+  to become undefined.
 
-Removes a normal variable from the current scope, causing it
-to become undefined.  If ``CACHE`` is present, then a cache variable
-is removed instead of a normal variable.
-
-If ``PARENT_SCOPE`` is present then the variable is removed from the scope
-above the current scope.  See the same option in the :command:`set` command
-for further details.
+  If ``PARENT_SCOPE`` is present then the variable is removed from the scope
+  above the current scope.  See the same option in the :command:`set` command
+  for further details.
 
 .. include:: include/UNSET_NOTE.rst
 
+Unset Cache Entry
+^^^^^^^^^^^^^^^^^
+
+.. signature::
+  unset(CACHE{<variable>})
+  :target: CACHE
+
+  .. versionadded:: 4.2
+
+  Removes ``<variable>`` from the cache, causing it to become undefined.
+
+.. signature::
+  unset(<variable> CACHE)
+  :target: CACHE_legacy
+
+  This signature is supported for compatibility purpose. Use preferably the
+  other one.
+
 Unset Environment Variable
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-.. code-block:: cmake
-
+.. signature::
   unset(ENV{<variable>})
+  :target: ENV
 
-Removes ``<variable>`` from the currently available
-:manual:`Environment Variables <cmake-env-variables(7)>`.
-Subsequent calls of ``$ENV{<variable>}`` will return the empty string.
+  Removes ``<variable>`` from the currently available
+  :manual:`Environment Variables <cmake-env-variables(7)>`.
+  Subsequent calls of ``$ENV{<variable>}`` will return the empty string.
 
-This command affects only the current CMake process, not the process
-from which CMake was called, nor the system environment at large,
-nor the environment of subsequent build or test processes.
+  This command affects only the current CMake process, not the process
+  from which CMake was called, nor the system environment at large,
+  nor the environment of subsequent build or test processes.
 
 See Also
 ^^^^^^^^
diff --git a/Help/dev/experimental.rst b/Help/dev/experimental.rst
index 81ddc8c..f5e4bd4 100644
--- a/Help/dev/experimental.rst
+++ b/Help/dev/experimental.rst
@@ -127,15 +127,15 @@
 set
 
 * variable ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` to
-* value ``a37d1069-1972-4901-b9c9-f194aaf2b6e0``.
+* value ``d16a3082-c4e1-489b-b90c-55750a334f27``.
 
 To enable instrumentation at the user-level, files should be placed under
 either
-``<CMAKE_CONFIG_DIR>/instrumentation-a37d1069-1972-4901-b9c9-f194aaf2b6e0`` or
-``<CMAKE_BINARY_DIR>/.cmake/instrumentation-a37d1069-1972-4901-b9c9-f194aaf2b6e0``.
+``<CMAKE_CONFIG_DIR>/instrumentation-d16a3082-c4e1-489b-b90c-55750a334f27`` or
+``<CMAKE_BINARY_DIR>/.cmake/instrumentation-d16a3082-c4e1-489b-b90c-55750a334f27``.
 
 To include instrumentation data in CTest XML files (for submission to CDash),
 you need to set the following environment variables:
 
 * ``CTEST_USE_INSTRUMENTATION=1``
-* ``CTEST_EXPERIMENTAL_INSTRUMENTATION=a37d1069-1972-4901-b9c9-f194aaf2b6e0``
+* ``CTEST_EXPERIMENTAL_INSTRUMENTATION=d16a3082-c4e1-489b-b90c-55750a334f27``
diff --git a/Help/envvar/CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY.rst b/Help/envvar/CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY.rst
new file mode 100644
index 0000000..1aab196
--- /dev/null
+++ b/Help/envvar/CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY.rst
@@ -0,0 +1,10 @@
+CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY
+---------------------------------------
+
+.. versionadded:: 4.2
+
+.. include:: include/ENV_VAR.rst
+
+``CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY`` is a string specifying the
+strategy to use for autogen-related target intermediate directories. It
+initializes the :variable:`CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY` variable.
diff --git a/Help/envvar/CMAKE_INTERMEDIATE_DIR_STRATEGY.rst b/Help/envvar/CMAKE_INTERMEDIATE_DIR_STRATEGY.rst
new file mode 100644
index 0000000..a3a01a7
--- /dev/null
+++ b/Help/envvar/CMAKE_INTERMEDIATE_DIR_STRATEGY.rst
@@ -0,0 +1,10 @@
+CMAKE_INTERMEDIATE_DIR_STRATEGY
+-------------------------------
+
+.. versionadded:: 4.2
+
+.. include:: include/ENV_VAR.rst
+
+``CMAKE_INTERMEDIATE_DIR_STRATEGY`` is a string specifying the strategy to use
+for target intermediate directories. It initializes the
+:variable:`CMAKE_INTERMEDIATE_DIR_STRATEGY` variable.
diff --git a/Help/envvar/CTEST_USE_INSTRUMENTATION.rst b/Help/envvar/CTEST_USE_INSTRUMENTATION.rst
index 6e33845..b00c92d 100644
--- a/Help/envvar/CTEST_USE_INSTRUMENTATION.rst
+++ b/Help/envvar/CTEST_USE_INSTRUMENTATION.rst
@@ -10,6 +10,6 @@
    This feature is only available when experimental support for instrumentation
    has been enabled by the ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` gate.
 
-Setting this environment variable enables
+Setting this environment variable to ``1``, ``True``, or ``ON`` enables
 :manual:`instrumentation <cmake-instrumentation(7)>` for CTest in
 :ref:`Dashboard Client` mode.
diff --git a/Help/envvar/CTEST_USE_VERBOSE_INSTRUMENTATION.rst b/Help/envvar/CTEST_USE_VERBOSE_INSTRUMENTATION.rst
index 95053e4..4a119aa 100644
--- a/Help/envvar/CTEST_USE_VERBOSE_INSTRUMENTATION.rst
+++ b/Help/envvar/CTEST_USE_VERBOSE_INSTRUMENTATION.rst
@@ -10,8 +10,9 @@
    This feature is only available when experimental support for instrumentation
    has been enabled by the ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` gate.
 
-Setting this environment variable causes CTest to report the full
-command line (including arguments) to CDash for each instrumented command.
-By default, CTest truncates the command line at the first space.
+Setting this environment variable to ``1``, ``True``, or ``ON`` causes CTest to
+report the full command line (including arguments) to CDash for each
+instrumented command. By default, CTest truncates the command line at the first
+space.
 
 See also :envvar:`CTEST_USE_INSTRUMENTATION`
diff --git a/Help/generator/Visual Studio 10 2010.rst b/Help/generator/Visual Studio 10 2010.rst
index 8b7e31d..08940d2 100644
--- a/Help/generator/Visual Studio 10 2010.rst
+++ b/Help/generator/Visual Studio 10 2010.rst
@@ -3,7 +3,7 @@
 
 Removed.  This once generated Visual Studio 10 2010 project files, but
 the generator has been removed since CMake 3.25.  It is still possible
-to build with the VS 10 2010 toolset by also installing VS 2015 (or above)
-and using the :generator:`Visual Studio 14 2015` (or above) generator with
+to build with the VS 10 2010 toolset by also installing VS 2017 (or above)
+and using the :generator:`Visual Studio 15 2017` (or above) generator with
 :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v100``,
 or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 11 2012.rst b/Help/generator/Visual Studio 11 2012.rst
index 99048bd..8c0f37c 100644
--- a/Help/generator/Visual Studio 11 2012.rst
+++ b/Help/generator/Visual Studio 11 2012.rst
@@ -3,7 +3,7 @@
 
 Removed.  This once generated Visual Studio 11 2012 project files, but
 the generator has been removed since CMake 3.28.  It is still possible
-to build with the VS 11 2012 toolset by also installing VS 2015 (or above)
-and using the :generator:`Visual Studio 14 2015` (or above) generator with
+to build with the VS 11 2012 toolset by also installing VS 2017 (or above)
+and using the :generator:`Visual Studio 15 2017` (or above) generator with
 :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v110``,
 or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 12 2013.rst b/Help/generator/Visual Studio 12 2013.rst
index 6589072..1724c0c 100644
--- a/Help/generator/Visual Studio 12 2013.rst
+++ b/Help/generator/Visual Studio 12 2013.rst
@@ -3,7 +3,7 @@
 
 Removed.  This once generated Visual Studio 12 2013 project files, but
 the generator has been removed since CMake 3.31.  It is still possible
-to build with the VS 12 2013 toolset by also installing VS 2015 (or above)
-and using the :generator:`Visual Studio 14 2015` (or above) generator with
+to build with the VS 12 2013 toolset by also installing VS 2017 (or above)
+and using the :generator:`Visual Studio 15 2017` (or above) generator with
 :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v120``,
 or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/generator/Visual Studio 14 2015.rst b/Help/generator/Visual Studio 14 2015.rst
index a491193..7e9035d 100644
--- a/Help/generator/Visual Studio 14 2015.rst
+++ b/Help/generator/Visual Studio 14 2015.rst
@@ -1,6 +1,14 @@
 Visual Studio 14 2015
 ---------------------
 
+.. deprecated:: 4.2
+
+  This generator is deprecated and will be removed in a future version
+  of CMake.  It will still be possible to build with VS 14 2015 tools
+  using the :generator:`Visual Studio 15 2017` (or above) generator
+  with :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v140``, or by
+  using the :generator:`NMake Makefiles` generator.
+
 .. versionadded:: 3.1
 
 Generates Visual Studio 14 (VS 2015) project files.
diff --git a/Help/generator/Visual Studio 9 2008.rst b/Help/generator/Visual Studio 9 2008.rst
index a5d953a..1e2730c 100644
--- a/Help/generator/Visual Studio 9 2008.rst
+++ b/Help/generator/Visual Studio 9 2008.rst
@@ -4,6 +4,6 @@
 Removed.  This once generated Visual Studio 9 2008 project files, but
 the generator has been removed since CMake 3.30.  It is still possible
 to build with the VS 9 2008 toolset by also installing VS 10 2010 and
-VS 2015 (or above) and using the :generator:`Visual Studio 14 2015`
+VS 2017 (or above) and using the :generator:`Visual Studio 15 2017`
 generator (or above) with :variable:`CMAKE_GENERATOR_TOOLSET` set to ``v90``,
 or by using the :generator:`NMake Makefiles` generator.
diff --git a/Help/include/ENVIRONMENT_MODIFICATION_OPS.rst b/Help/include/ENVIRONMENT_MODIFICATION_OPS.rst
new file mode 100644
index 0000000..9ef4b14
--- /dev/null
+++ b/Help/include/ENVIRONMENT_MODIFICATION_OPS.rst
@@ -0,0 +1,20 @@
+- ``reset``: Reset to the unmodified value, ignoring all modifications to
+  ``MYVAR`` prior to this entry. Note that this will reset the variable to
+  the value set by :prop_test:`ENVIRONMENT`, if it was set, and otherwise
+  to its state from the rest of the CTest execution.
+- ``set``: Replaces the current value of ``MYVAR`` with ``VALUE``.
+- ``unset``: Unsets the current value of ``MYVAR``.
+- ``string_append``: Appends singular ``VALUE`` to the current value of
+  ``MYVAR``.
+- ``string_prepend``: Prepends singular ``VALUE`` to the current value of
+  ``MYVAR``.
+- ``path_list_append``: Appends singular ``VALUE`` to the current value of
+  ``MYVAR`` using the host platform's path list separator (``;`` on Windows
+  and ``:`` elsewhere).
+- ``path_list_prepend``: Prepends singular ``VALUE`` to the current value of
+  ``MYVAR`` using the host platform's path list separator (``;`` on Windows
+  and ``:`` elsewhere).
+- ``cmake_list_append``: Appends singular ``VALUE`` to the current value of
+  ``MYVAR`` using ``;`` as the separator.
+- ``cmake_list_prepend``: Prepends singular ``VALUE`` to the current value of
+  ``MYVAR`` using ``;`` as the separator.
diff --git a/Help/manual/cmake-developer.7.rst b/Help/manual/cmake-developer.7.rst
index f7896e5..7e1f61b 100644
--- a/Help/manual/cmake-developer.7.rst
+++ b/Help/manual/cmake-developer.7.rst
@@ -154,7 +154,7 @@
 ``Foo_FIND_COMPONENTS`` if it is set , and only set ``Foo_FOUND`` to
 true if for each searched-for component ``<c>`` that was not found,
 ``Foo_FIND_REQUIRED_<c>`` is not set to true.  The ``HANDLE_COMPONENTS``
-argument of ``find_package_handle_standard_args()`` can be used to
+argument of :command:`find_package_handle_standard_args` can be used to
 implement this.
 
 If ``Foo_FIND_COMPONENTS`` is not set, which modules are searched for
diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst
index e493655..156b800 100644
--- a/Help/manual/cmake-env-variables.7.rst
+++ b/Help/manual/cmake-env-variables.7.rst
@@ -44,6 +44,7 @@
 
    /envvar/ADSP_ROOT
    /envvar/CMAKE_APPLE_SILICON_PROCESSOR
+   /envvar/CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY
    /envvar/CMAKE_BUILD_PARALLEL_LEVEL
    /envvar/CMAKE_BUILD_TYPE
    /envvar/CMAKE_COLOR_DIAGNOSTICS
@@ -65,6 +66,7 @@
    /envvar/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES_EXCLUDE
    /envvar/CMAKE_LANG_LINKER_LAUNCHER
    /envvar/CMAKE_MSVCIDE_RUN_PATH
+   /envvar/CMAKE_INTERMEDIATE_DIR_STRATEGY
    /envvar/CMAKE_NO_VERBOSE
    /envvar/CMAKE_OSX_ARCHITECTURES
    /envvar/CMAKE_TEST_LAUNCHER
diff --git a/Help/manual/cmake-file-api.7.rst b/Help/manual/cmake-file-api.7.rst
index 058e4aa..3266cc9 100644
--- a/Help/manual/cmake-file-api.7.rst
+++ b/Help/manual/cmake-file-api.7.rst
@@ -125,6 +125,10 @@
 This can be used to avoid asking CMake to generate multiple object
 versions unnecessarily.
 
+.. versionadded:: 4.1
+  The ``query.json`` file is described in machine-readable form by
+  :download:`this JSON schema </manual/file_api/schema_stateful_query.json>`.
+
 A ``query.json`` file must contain a JSON object:
 
 .. code-block:: json
@@ -200,6 +204,10 @@
 the one with the largest name in lexicographic order is the current
 index file.
 
+.. versionadded:: 4.1
+  The reply index file is described in machine-readable form by
+  :download:`this JSON schema </manual/file_api/schema_index.json>`.
+
 The reply index file contains a JSON object:
 
 .. code-block:: json
@@ -471,6 +479,10 @@
 Version 1 does not exist to avoid confusion with that from
 :manual:`cmake-server(7)` mode.
 
+.. versionadded:: 4.1
+  The ``codemodel`` object kind reply is described in machine-readable form
+  by :download:`this JSON schema </manual/file_api/schema_codemodel.json>`.
+
 "codemodel" version 2
 ^^^^^^^^^^^^^^^^^^^^^
 
@@ -700,10 +712,27 @@
 "codemodel" version 2 "directory" object
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 4.1
+  The ``directory`` object reply is described in machine-readable form by
+  :download:`this JSON schema </manual/file_api/schema_directory.json>`.
+
 A codemodel "directory" object is referenced by a `"codemodel" version 2`_
 object's ``directories`` array.  Each "directory" object is a JSON object
 with members:
 
+``codemodelVersion``
+  This specifies the codemodel version this file is part of.  It will match
+  the ``version`` field of the codemodel object kind that references this file.
+  It is a JSON object with the following members:
+
+  ``major``
+    The codemodel major version.
+
+  ``minor``
+    The codemodel minor version.
+
+  This field was added in codemodel version 2.9.
+
 ``paths``
   A JSON object containing members:
 
@@ -976,10 +1005,27 @@
 "codemodel" version 2 "target" object
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+.. versionadded:: 4.1
+  The ``target`` object reply is described in machine-readable form by
+  :download:`this JSON schema </manual/file_api/schema_target.json>`.
+
 A codemodel "target" object is referenced by a `"codemodel" version 2`_
 object's ``targets`` array.  Each "target" object is a JSON object
 with members:
 
+``codemodelVersion``
+  This specifies the codemodel version this file is part of.  It will match
+  the ``version`` field of the codemodel object kind that references this file.
+  It is a JSON object with the following members:
+
+  ``major``
+    The codemodel major version.
+
+  ``minor``
+    The codemodel minor version.
+
+  This field was added in codemodel version 2.9.
+
 ``name``
   A string specifying the logical name of the target.
 
@@ -1471,6 +1517,10 @@
 
 There is only one ``configureLog`` object major version, version 1.
 
+.. versionadded:: 4.1
+  The ``configureLog`` object kind reply is described in machine-readable form
+  by :download:`this JSON schema </manual/file_api/schema_configureLog.json>`.
+
 "configureLog" version 1
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1511,6 +1561,10 @@
 Version 1 does not exist to avoid confusion with that from
 :manual:`cmake-server(7)` mode.
 
+.. versionadded:: 4.1
+  The ``cache`` object kind reply is described in machine-readable form by
+  :download:`this JSON schema </manual/file_api/schema_cache.json>`.
+
 "cache" version 2
 ^^^^^^^^^^^^^^^^^
 
@@ -1583,6 +1637,10 @@
 
 There is only one ``cmakeFiles`` object major version, version 1.
 
+.. versionadded:: 4.1
+  The ``cmakeFiles`` object kind reply is described in machine-readable form
+  by :download:`this JSON schema </manual/file_api/schema_cmakeFiles.json>`.
+
 "cmakeFiles" version 1
 ^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1712,6 +1770,10 @@
 
 There is only one ``toolchains`` object major version, version 1.
 
+.. versionadded:: 4.1
+  The ``toolchains`` object kind reply is described in machine-readable form
+  by :download:`this JSON schema </manual/file_api/schema_toolchains.json>`.
+
 "toolchains" version 1
 ^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index 4bc0435..b031246 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -1420,8 +1420,8 @@
   Note that for proper evaluation of this expression requires policy :policy:`CMP0099`
   to be set to ``NEW``.
 
-Linker Language And ID
-^^^^^^^^^^^^^^^^^^^^^^
+Link Language and ID
+^^^^^^^^^^^^^^^^^^^^
 
 .. genex:: $<LINK_LANGUAGE>
 
@@ -1827,6 +1827,209 @@
   (see :genex:`$<DEVICE_LINK:list>` generator expression). This expression can
   only be used to specify link options.
 
+Linker ID and Frontend-Variant
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+See also the :variable:`CMAKE_<LANG>_COMPILER_LINKER_ID` and
+:variable:`CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT` variables, which are
+closely related to most of the expressions in this sub-section.
+
+.. genex:: $<C_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the C linker used.
+
+.. genex:: $<C_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the C linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<CXX_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the C++ linker used.
+
+.. genex:: $<CXX_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the C++ linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<CUDA_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the CUDA linker used.
+
+.. genex:: $<CUDA_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the CUDA linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<OBJC_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the Objective-C linker used.
+
+.. genex:: $<OBJC_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the Objective-C linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the Objective-C++ linker used.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the Objective-C++ linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<Fortran_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the Fortran linker used.
+
+.. genex:: $<Fortran_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the Fortran linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<HIP_COMPILER_LINKER_ID>
+
+  .. versionadded:: 4.2
+
+  CMake's linker id of the HIP linker used.
+
+.. genex:: $<HIP_COMPILER_LINKER_ID:linker_ids>
+
+  .. versionadded:: 4.2
+
+  where ``linker_ids`` is a comma-separated list.
+  ``1`` if CMake's linker id of the HIP linker matches any one
+  of the entries in ``linker_ids``, otherwise ``0``.
+
+.. genex:: $<C_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the C linker used.
+
+.. genex:: $<C_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the C linker matches any one
+  of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<CXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the C++ linker used.
+
+.. genex:: $<CXX_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the C++ linker matches any one
+  of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<CUDA_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the CUDA linker used.
+
+.. genex:: $<CUDA_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the CUDA linker matches any one
+  of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<OBJC_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the Objective-C linker used.
+
+.. genex:: $<OBJC_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the Objective-C linker matches
+  any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the Objective-C++ linker used.
+
+.. genex:: $<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the Objective-C++ linker matches
+  any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<Fortran_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the Fortran linker used.
+
+.. genex:: $<Fortran_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the Fortran linker matches
+  any one of the entries in ``variant_ids``, otherwise ``0``.
+
+.. genex:: $<HIP_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  .. versionadded:: 4.2
+
+  CMake's linker frontend variant of the HIP linker used.
+
+.. genex:: $<HIP_COMPILER_LINKER_FRONTEND_VARIANT:variant_ids>
+
+  .. versionadded:: 4.2
+
+  where ``variant_ids`` is a comma-separated list.
+  ``1`` if CMake's linker frontend variant of the HIP linker matches
+  any one of the entries in ``variant_ids``, otherwise ``0``.
+
 
 .. _`Target-Dependent Expressions`:
 
diff --git a/Help/manual/cmake-instrumentation.7.rst b/Help/manual/cmake-instrumentation.7.rst
index e20d8a6..06e71ed 100644
--- a/Help/manual/cmake-instrumentation.7.rst
+++ b/Help/manual/cmake-instrumentation.7.rst
@@ -98,9 +98,8 @@
 ----------------------------------------------
 
 You can enable instrumentation when using CTest in :ref:`Dashboard Client`
-mode by setting the :envvar:`CTEST_USE_INSTRUMENTATION` environment variable
-to the current UUID for the ``CMAKE_EXPERIMENTAL_INSTRUMENTATION`` feature.
-Doing so automatically enables the ``dynamicSystemInformation`` query.
+mode by setting the :envvar:`CTEST_USE_INSTRUMENTATION` environment variable.
+Doing so automatically enables the ``dynamicSystemInformation`` option.
 
 The following table shows how each type of instrumented command gets mapped
 to a corresponding type of CTest XML file.
@@ -125,13 +124,17 @@
 You can instead choose to report the full command line (including arguments)
 by setting :envvar:`CTEST_USE_VERBOSE_INSTRUMENTATION` to 1.
 
+Alternatively, you can use the `v1 Query Files`_ to enable instrumentation for
+CDash using the ``cdashSubmit`` and ``cdashVerbose`` options.
+
 .. _`cmake-instrumentation API v1`:
 
 API v1
 ======
 
-The API version specifies both the subdirectory layout of the instrumentation data,
-and the format of the query files.
+The API version specifies the layout of the instrumentation directory, as well
+as the general format of the query files and :command:`cmake_instrumentation`
+command arguments.
 
 The Instrumentation API v1 is housed  in the ``instrumentation/v1/`` directory
 under either ``<build>/.cmake/`` for output data and project-level queries, or
@@ -146,8 +149,9 @@
 
 ``query/generated/``
   Holds query files generated by a CMake project with the
-  :command:`cmake_instrumentation` command. These files are owned by CMake and
-  are deleted and regenerated automatically during the CMake configure step.
+  :command:`cmake_instrumentation` command or the
+  :envvar:`CTEST_USE_INSTRUMENTATION` variable. These files are owned by CMake
+  and are deleted and regenerated automatically during the CMake configure step.
 
 ``data/``
   Holds instrumentation data collected on the project. CMake owns all data
@@ -185,16 +189,21 @@
   should be one of the following:
 
   * ``postGenerate``
-  * ``preBuild`` (called when ``ninja``  or ``make`` is invoked; unavailable on Windows)
-  * ``postBuild`` (called when ``ninja`` or ``make`` completes; unavailable on Windows)
+  * ``preBuild`` (called when ``ninja``  or ``make`` is invoked)
+  * ``postBuild`` (called when ``ninja`` or ``make`` completes)
   * ``preCMakeBuild`` (called when ``cmake --build`` is invoked)
   * ``postCMakeBuild`` (called when ``cmake --build`` completes)
   * ``postInstall``
   * ``postTest``
 
-``queries``
-  A list of strings specifying additional optional data to collect during
-  instrumentation. Elements in this list should be one of the following:
+  ``preBuild`` and ``postBuild`` are not supported with the
+  :generator:`MSYS Makefiles` generator. Additionally, they will not be
+  triggered when the build tool is invoked by ``cmake --build``.
+
+``options``
+  A list of strings used to enable certain optional behavior, including the
+  collection of certain additional data. Elements in this list should be one of
+  the following:
 
     ``staticSystemInformation``
       Enables collection of the static information about the host machine CMake
@@ -207,13 +216,26 @@
       generated by CMake, and includes information from immediately before and
       after the command is executed.
 
+    ``cdashSubmit``
+      Enables including instrumentation data in CDash. This does not
+      automatically enable ``dynamicSystemInformation``, but is otherwise
+      equivalent to having the :envvar:`CTEST_USE_INSTRUMENTATION` environment
+      variable enabled.
+
+    ``cdashVerbose``
+      Enables including the full untruncated commands in data submitted to
+      CDash. Equivalent to having the
+      :envvar:`CTEST_USE_VERBOSE_INSTRUMENTATION` environment variable enabled.
+
 The ``callbacks`` listed will be invoked during the specified hooks
 *at a minimum*. When there are multiple query files, the ``callbacks``,
-``hooks`` and ``queries`` between them will be merged. Therefore, if any query
+``hooks`` and ``options`` between them will be merged. Therefore, if any query
 file includes any ``hooks``, every ``callback`` across all query files will be
 executed at every ``hook`` across all query files. Additionally, if any query
-file includes any optional ``queries``, the optional query data will be present
-in all data files.
+file requests optional data using the ``options`` field, any related data will
+be present in all snippet files. User written ``callbacks`` should be able to
+handle the presence of this optional data, since it may be requested by an
+unrelated query.
 
 Example:
 
@@ -229,9 +251,10 @@
       "postCMakeBuild",
       "postInstall"
     ],
-    "queries": [
+    "options": [
       "staticSystemInformation",
-      "dynamicSystemInformation"
+      "dynamicSystemInformation",
+      "cdashSubmit"
     ]
   }
 
@@ -240,12 +263,14 @@
 ``<build>/.cmake/instrumentation/v1/data`` containing a list of data snippet
 files created since the previous indexing. The commands
 ``/usr/bin/python callback.py index-<timestamp>.json`` and
-``/usr/bin/cmake -P callback.cmake arg index-<timestamp>.json`` will be executed in
-that order. The index file will contain the ``staticSystemInformation`` data and
-each snippet file listed in the index will contain the
+``/usr/bin/cmake -P callback.cmake arg index-<timestamp>.json`` will be executed
+in that order. The index file will contain the ``staticSystemInformation`` data
+and each snippet file listed in the index will contain the
 ``dynamicSystemInformation`` data. Once both callbacks have completed, the index
 file and all snippet files listed by it will be deleted from the project build
-tree.
+tree. The instrumentation data will be present in the XML files submitted to
+CDash, but with truncated command strings because ``cdashVerbose`` was not
+enabled.
 
 .. _`cmake-instrumentation Data v1`:
 
@@ -253,10 +278,13 @@
 =======
 
 Data version specifies the contents of the output files generated by the CMake
-instrumentation API as part of the `Data Collection`_ and `Indexing`_. There are
-two types of data files generated: the `v1 Snippet File`_ and `v1 Index File`_.
-When using the `API v1`_, these files live in
-``<build>/.cmake/instrumentation/v1/data/`` under the project build tree.
+instrumentation API as part of the `Data Collection`_ and `Indexing`_. A new
+version number will be created whenever previously included data is removed or
+reformatted such that scripts written to parse this data may become
+incompatible with the new format. There are two types of data files generated:
+the `v1 Snippet File`_ and `v1 Index File`_. When using the `API v1`_, these
+files live in ``<build>/.cmake/instrumentation/v1/data/`` under the project
+build tree.
 
 v1 Snippet File
 ---------------
diff --git a/Help/manual/cmake-language.7.rst b/Help/manual/cmake-language.7.rst
index d590b5a..908c46c 100644
--- a/Help/manual/cmake-language.7.rst
+++ b/Help/manual/cmake-language.7.rst
@@ -12,6 +12,8 @@
 
 CMake input files are written in the "CMake Language" in source files
 named ``CMakeLists.txt`` or ending in a ``.cmake`` file name extension.
+The term *listfile* is a general name for any such source file containing
+CMake commands that the tool processes.
 
 CMake Language source files in a project are organized into:
 
diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst
index d9b9f2e..265a128 100644
--- a/Help/manual/cmake-modules.7.rst
+++ b/Help/manual/cmake-modules.7.rst
@@ -30,8 +30,8 @@
    /module/CheckFortranSourceCompiles
    /module/CheckFortranSourceRuns
    /module/CheckFunctionExists
-   /module/CheckIncludeFileCXX
    /module/CheckIncludeFile
+   /module/CheckIncludeFileCXX
    /module/CheckIncludeFiles
    /module/CheckIPOSupported
    /module/CheckLanguage
@@ -55,8 +55,6 @@
    /module/CMakeBackwardCompatibilityCXX
    /module/CMakeDependentOption
    /module/CMakeFindDependencyMacro
-   /module/CMakeFindPackageMode
-   /module/CMakeGraphVizOptions
    /module/CMakePackageConfigHelpers
    /module/CMakePrintHelpers
    /module/CMakePrintSystemInformation
@@ -69,7 +67,6 @@
    /module/CSharpUtilities
    /module/CTest
    /module/CTestCoverageCollectGCOV
-   /module/CTestScriptMode
    /module/CTestUseLaunchers
    /module/DeployQt4
    /module/ExternalData
@@ -186,7 +183,6 @@
    /module/FindOpenSSL
    /module/FindOpenThreads
    /module/Findosg
-   /module/Findosg_functions
    /module/FindosgAnimation
    /module/FindosgDB
    /module/FindosgFX
@@ -232,8 +228,8 @@
    /module/FindSDL_sound
    /module/FindSDL_ttf
    /module/FindSelfPackers
-   /module/FindSquish
    /module/FindSQLite3
+   /module/FindSquish
    /module/FindSubversion
    /module/FindSWIG
    /module/FindTCL
@@ -271,7 +267,6 @@
    /module/Documentation
    /module/GetPrerequisites
    /module/MacroAddFileDependencies
-   /module/SquishTestScript
    /module/TestBigEndian
    /module/TestCXXAcceptsFlag
    /module/Use_wxWindows
@@ -322,3 +317,17 @@
    /module/CPackProductBuild
    /module/CPackRPM
    /module/CPackWIX
+
+Miscellaneous Modules
+---------------------
+
+These internal modules are not intended to be included directly in projects:
+
+.. toctree::
+   :maxdepth: 1
+
+   /module/CMakeFindPackageMode
+   /module/CMakeGraphVizOptions
+   /module/CTestScriptMode
+   /module/Findosg_functions
+   /module/SquishTestScript
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 45e0ca0..4dbabed 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -34,10 +34,10 @@
 
 .. code-block:: cmake
 
-  cmake_minimum_required(VERSION 3.10...4.0)
+  cmake_minimum_required(VERSION 3.10...4.1)
 
 This uses the ``<min>...<max>`` syntax to enable the ``NEW`` behaviors
-of policies introduced in CMake 4.0 and earlier while only requiring a
+of policies introduced in CMake 4.1 and earlier while only requiring a
 minimum version of CMake 3.10.  The project is expected to work with
 both the ``OLD`` and ``NEW`` behaviors of policies introduced between
 those versions.
@@ -92,6 +92,15 @@
 
 The following policies are supported.
 
+Policies Introduced by CMake 4.2
+--------------------------------
+
+.. toctree::
+   :maxdepth: 1
+
+   CMP0199: $<CONFIG> only matches the configuration of the consumed target. </policy/CMP0199>
+   CMP0198: CMAKE_PARENT_LIST_FILE is not defined in CMakeLists.txt. </policy/CMP0198>
+
 Policies Introduced by CMake 4.1
 --------------------------------
 
diff --git a/Help/manual/cmake-presets.7.rst b/Help/manual/cmake-presets.7.rst
index 9400a1b..b0f8e03 100644
--- a/Help/manual/cmake-presets.7.rst
+++ b/Help/manual/cmake-presets.7.rst
@@ -270,8 +270,8 @@
 ``graphviz``
   An optional string representing the path to the graphviz input file,
   that will contain all the library and executable dependencies
-  in the project. See the documentation for :module:`CMakeGraphVizOptions`
-  for more details.
+  in the project.  See the documentation for :option:`cmake --graphviz` for
+  more details.
 
   This field supports `macro expansion`_. If a relative path is specified,
   it is calculated relative to the current working directory. It is allowed
@@ -1083,9 +1083,25 @@
 ``packageName``
   An optional string representing the package name.
 
+  .. note::
+
+    Due to problems with the implementation, this field does not affect the
+    name of the final package file produced.  Other aspects of the package
+    may use the value though, leading to inconsistencies.
+    A future CMake release may address this problem, but until then, it is
+    recommended that this field not be used.
+
 ``packageVersion``
   An optional string representing the package version.
 
+  .. note::
+
+    Due to problems with the implementation, this field does not affect the
+    name of the final package file produced.  Other aspects of the package
+    may use the value though, leading to inconsistencies.
+    A future CMake release may address this problem, but until then, it is
+    recommended that this field not be used.
+
 ``packageDirectory``
   An optional string representing the directory in which to place the package.
 
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index a2b88dd..63622a8 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -580,6 +580,7 @@
    /prop_sf/MACOSX_PACKAGE_LOCATION
    /prop_sf/OBJECT_DEPENDS
    /prop_sf/OBJECT_OUTPUTS
+   /prop_sf/JOB_POOL_COMPILE
    /prop_sf/SKIP_AUTOGEN
    /prop_sf/SKIP_AUTOMOC
    /prop_sf/SKIP_AUTORCC
diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst
index 9eee219..cbd1f74 100644
--- a/Help/manual/cmake-toolchains.7.rst
+++ b/Help/manual/cmake-toolchains.7.rst
@@ -704,3 +704,22 @@
 
 - Use :command:`find_package` only for libraries installed with
   :variable:`CMAKE_IOS_INSTALL_COMBINED` feature
+
+.. _`Cross Compiling for Emscripten`:
+
+Cross Compiling for Emscripten
+------------------------------
+
+.. versionadded:: 4.2
+
+A toolchain file may configure cross-compiling for `Emscripten`_ by
+setting the :variable:`CMAKE_SYSTEM_NAME` variable to ``Emscripten``.
+For example, a toolchain file might contain:
+
+.. code-block:: cmake
+
+  set(CMAKE_SYSTEM_NAME Emscripten)
+  set(CMAKE_C_COMPILER /path/to/emcc)
+  set(CMAKE_CXX_COMPILER /path/to/em++)
+
+.. _`Emscripten`: https://emscripten.org/
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index d3ff681..c936f50 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -98,15 +98,16 @@
    /variable/CMAKE_OBJDUMP
    /variable/CMAKE_PARENT_LIST_FILE
    /variable/CMAKE_PATCH_VERSION
+   /variable/CMAKE_PROJECT_COMPAT_VERSION
    /variable/CMAKE_PROJECT_DESCRIPTION
    /variable/CMAKE_PROJECT_HOMEPAGE_URL
    /variable/CMAKE_PROJECT_NAME
+   /variable/CMAKE_PROJECT_SPDX_LICENSE
    /variable/CMAKE_PROJECT_VERSION
    /variable/CMAKE_PROJECT_VERSION_MAJOR
    /variable/CMAKE_PROJECT_VERSION_MINOR
    /variable/CMAKE_PROJECT_VERSION_PATCH
    /variable/CMAKE_PROJECT_VERSION_TWEAK
-   /variable/CMAKE_PROJECT_COMPAT_VERSION
    /variable/CMAKE_RANLIB
    /variable/CMAKE_ROOT
    /variable/CMAKE_RULE_MESSAGES
@@ -154,28 +155,30 @@
    /variable/CMAKE_XCODE_BUILD_SYSTEM
    /variable/CMAKE_XCODE_PLATFORM_TOOLSET
    /variable/PROJECT-NAME_BINARY_DIR
+   /variable/PROJECT-NAME_COMPAT_VERSION
    /variable/PROJECT-NAME_DESCRIPTION
    /variable/PROJECT-NAME_HOMEPAGE_URL
    /variable/PROJECT-NAME_IS_TOP_LEVEL
    /variable/PROJECT-NAME_SOURCE_DIR
+   /variable/PROJECT-NAME_SPDX_LICENSE
    /variable/PROJECT-NAME_VERSION
    /variable/PROJECT-NAME_VERSION_MAJOR
    /variable/PROJECT-NAME_VERSION_MINOR
    /variable/PROJECT-NAME_VERSION_PATCH
    /variable/PROJECT-NAME_VERSION_TWEAK
-   /variable/PROJECT-NAME_COMPAT_VERSION
    /variable/PROJECT_BINARY_DIR
+   /variable/PROJECT_COMPAT_VERSION
    /variable/PROJECT_DESCRIPTION
    /variable/PROJECT_HOMEPAGE_URL
    /variable/PROJECT_IS_TOP_LEVEL
    /variable/PROJECT_NAME
    /variable/PROJECT_SOURCE_DIR
+   /variable/PROJECT_SPDX_LICENSE
    /variable/PROJECT_VERSION
    /variable/PROJECT_VERSION_MAJOR
    /variable/PROJECT_VERSION_MINOR
    /variable/PROJECT_VERSION_PATCH
    /variable/PROJECT_VERSION_TWEAK
-   /variable/PROJECT_COMPAT_VERSION
 
 Variables that Change Behavior
 ==============================
@@ -188,6 +191,7 @@
    /variable/CMAKE_ABSOLUTE_DESTINATION_FILES
    /variable/CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY
    /variable/CMAKE_APPBUNDLE_PATH
+   /variable/CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY
    /variable/CMAKE_BUILD_TYPE
    /variable/CMAKE_CLANG_VFS_OVERLAY
    /variable/CMAKE_CODEBLOCKS_COMPILER_ID
@@ -258,6 +262,7 @@
    /variable/CMAKE_MESSAGE_LOG_LEVEL
    /variable/CMAKE_MFC_FLAG
    /variable/CMAKE_MODULE_PATH
+   /variable/CMAKE_INTERMEDIATE_DIR_STRATEGY
    /variable/CMAKE_PKG_CONFIG_DISABLE_UNINSTALLED
    /variable/CMAKE_PKG_CONFIG_PC_LIB_DIRS
    /variable/CMAKE_PKG_CONFIG_PC_PATH
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index 46ad589..316ba25 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -252,11 +252,145 @@
 
 .. option:: --graphviz=<file>
 
- Generate graphviz of dependencies, see :module:`CMakeGraphVizOptions` for more.
+  Generate `Graphviz <https://www.graphviz.org/>`_ of dependencies
 
- Generate a graphviz input file that will contain all the library and
- executable dependencies in the project.  See the documentation for
- :module:`CMakeGraphVizOptions` for more details.
+  This option generates a graphviz input file that will contain all the
+  library and executable dependencies in the project showing the
+  dependencies between the targets in a project, as well as external libraries
+  which are linked against.
+
+  When running CMake with the ``--graphviz=foo.dot`` option, it produces:
+
+  * a ``foo.dot`` file, showing all dependencies in the project
+  * a ``foo.dot.<target>`` file for each target, showing on which other targets
+    it depends
+  * a ``foo.dot.<target>.dependers`` file for each target, showing which other
+    targets depend on it
+
+  Those .dot files can be converted to images using the *dot* command from the
+  Graphviz package:
+
+  .. code-block:: shell
+
+    dot -Tpng -o foo.png foo.dot
+
+  .. versionadded:: 3.10
+    The different dependency types ``PUBLIC``, ``INTERFACE`` and ``PRIVATE``
+    are represented as solid, dashed and dotted edges.
+
+  .. rubric:: Variables specific to the Graphviz support
+
+  The resulting graphs can be huge.  The look and content of the generated graphs
+  can be controlled using the file ``CMakeGraphVizOptions.cmake``.  This file is
+  first searched in :variable:`CMAKE_BINARY_DIR`, and then in
+  :variable:`CMAKE_SOURCE_DIR`.  If found, the variables set in it are used to
+  adjust options for the generated Graphviz files.
+
+  .. variable:: GRAPHVIZ_GRAPH_NAME
+
+    The graph name.
+
+    * Mandatory: NO
+    * Default: value of :variable:`CMAKE_PROJECT_NAME`
+
+  .. variable:: GRAPHVIZ_GRAPH_HEADER
+
+    The header written at the top of the Graphviz files.
+
+    * Mandatory: NO
+    * Default: "node [ fontsize = "12" ];"
+
+  .. variable:: GRAPHVIZ_NODE_PREFIX
+
+    The prefix for each node in the Graphviz files.
+
+    * Mandatory: NO
+    * Default: "node"
+
+  .. variable:: GRAPHVIZ_EXECUTABLES
+
+    Set to FALSE to exclude executables from the generated graphs.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_STATIC_LIBS
+
+    Set to FALSE to exclude static libraries from the generated graphs.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_SHARED_LIBS
+
+    Set to FALSE to exclude shared libraries from the generated graphs.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_MODULE_LIBS
+
+    Set to FALSE to exclude module libraries from the generated graphs.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_INTERFACE_LIBS
+
+    Set to FALSE to exclude interface libraries from the generated graphs.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_OBJECT_LIBS
+
+    Set to FALSE to exclude object libraries from the generated graphs.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_UNKNOWN_LIBS
+
+    Set to FALSE to exclude unknown libraries from the generated graphs.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_EXTERNAL_LIBS
+
+    Set to FALSE to exclude external libraries from the generated graphs.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_CUSTOM_TARGETS
+
+    Set to TRUE to include custom targets in the generated graphs.
+
+    * Mandatory: NO
+    * Default: FALSE
+
+  .. variable:: GRAPHVIZ_IGNORE_TARGETS
+
+    A list of regular expressions for names of targets to exclude from the
+    generated graphs.
+
+    * Mandatory: NO
+    * Default: empty
+
+  .. variable:: GRAPHVIZ_GENERATE_PER_TARGET
+
+    Set to FALSE to not generate per-target graphs ``foo.dot.<target>``.
+
+    * Mandatory: NO
+    * Default: TRUE
+
+  .. variable:: GRAPHVIZ_GENERATE_DEPENDERS
+
+    Set to FALSE to not generate depender graphs ``foo.dot.<target>.dependers``.
+
+    * Mandatory: NO
+    * Default: TRUE
 
 .. option:: --system-information [file]
 
@@ -1029,6 +1163,19 @@
   ``copy_directory_if_different`` does follow symlinks.
   The command fails when the source directory does not exist.
 
+.. option:: copy_directory_if_newer <dir>... <destination>
+
+  .. versionadded:: 4.2
+
+  Copy content of ``<dir>...`` directories to ``<destination>`` directory
+  if source files are newer than destination files (based on file timestamps).
+  If ``<destination>`` directory does not exist it will be created.
+
+  ``copy_directory_if_newer`` does follow symlinks.
+  The command fails when the source directory does not exist.
+  This is faster than ``copy_directory_if_different`` as it only compares
+  file timestamps instead of file contents.
+
 .. option:: copy_if_different <file>... <destination>
 
   Copy files to ``<destination>`` (either file or directory) if
@@ -1040,6 +1187,18 @@
   .. versionadded:: 3.5
     Support for multiple input files.
 
+.. option:: copy_if_newer <file>... <destination>
+
+  .. versionadded:: 4.2
+
+  Copy files to ``<destination>`` (either file or directory) if
+  source files are newer than destination files (based on file timestamps).
+  If multiple files are specified, the ``<destination>`` must be
+  directory and it must exist.
+  ``copy_if_newer`` does follow symlinks.
+  This is faster than ``copy_if_different`` as it only compares
+  file timestamps instead of file contents.
+
 .. option:: create_symlink <old> <new>
 
   Create a symbolic link ``<new>`` naming ``<old>``.
diff --git a/Help/manual/file_api/schema_cache.json b/Help/manual/file_api/schema_cache.json
new file mode 100644
index 0000000..78ebf8e
--- /dev/null
+++ b/Help/manual/file_api/schema_cache.json
@@ -0,0 +1,83 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "description": "Schema for the CMake cache object kind",
+  "type": "object",
+  "required": [
+    "kind",
+    "version",
+    "entries"
+  ],
+  "properties": {
+    "kind": {
+      "type": "string",
+      "const": "cache"
+    },
+    "version": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 2
+        },
+        "minor": {
+          "type": "integer",
+          "const": 0
+        }
+      },
+      "additionalProperties": false
+    },
+    "entries": {
+      "type": "array",
+      "description": "Array of CMake cache entries",
+      "items": {
+        "type": "object",
+        "required": [
+          "name",
+          "value",
+          "type",
+          "properties"
+        ],
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "Name of the cache entry"
+          },
+          "value": {
+            "type": "string",
+            "description": "Value of the cache entry"
+          },
+          "type": {
+            "type": "string",
+            "description": "Type of the cache entry used by CMake GUI to choose a widget for editing"
+          },
+          "properties": {
+            "type": "array",
+            "description": "Associated properties for the cache entry",
+            "items": {
+              "type": "object",
+              "required": [
+                "name",
+                "value"
+              ],
+              "properties": {
+                "name": {
+                  "type": "string"
+                },
+                "value": {
+                  "type": "string"
+                }
+              },
+              "additionalProperties": false
+            }
+          }
+        },
+        "additionalProperties": false
+      }
+    }
+  },
+  "additionalProperties": false
+}
diff --git a/Help/manual/file_api/schema_cmakeFiles.json b/Help/manual/file_api/schema_cmakeFiles.json
new file mode 100644
index 0000000..3611825
--- /dev/null
+++ b/Help/manual/file_api/schema_cmakeFiles.json
@@ -0,0 +1,186 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "description": "Schema for the CMake cmakeFiles object kind",
+  "type": "object",
+  "required": [
+    "kind",
+    "version",
+    "paths",
+    "inputs"
+  ],
+  "oneOf": [
+    {
+      "$ref": "#/definitions/cmakeFilesV1_0"
+    },
+    {
+      "$ref": "#/definitions/cmakeFilesV1_1"
+    }
+  ],
+  "definitions": {
+    "kind": {
+      "type": "string",
+      "const": "cmakeFiles",
+      "description": "Specifies the object kind"
+    },
+    "versionV1_0": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 1
+        },
+        "minor": {
+          "type": "integer",
+          "const": 0
+        }
+      },
+      "additionalProperties": false
+    },
+    "versionV1_1": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 1
+        },
+        "minor": {
+          "type": "integer",
+          "const": 1
+        }
+      },
+      "additionalProperties": false
+    },
+    "paths": {
+      "type": "object",
+      "required": [
+        "build",
+        "source"
+      ],
+      "properties": {
+        "build": {
+          "type": "string",
+          "description": "Absolute path to the top-level build directory"
+        },
+        "source": {
+          "type": "string",
+          "description": "Absolute path to the top-level source directory"
+        }
+      },
+      "additionalProperties": false
+    },
+    "inputs": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "path"
+        ],
+        "properties": {
+          "path": {
+            "type": "string",
+            "description": "Path to an input file to CMake"
+          },
+          "isGenerated": {
+            "type": "boolean",
+            "description": "Indicates if the file is under the build directory in out-of-source builds"
+          },
+          "isExternal": {
+            "type": "boolean",
+            "description": "Indicates if the file is not under source or build directories"
+          },
+          "isCMake": {
+            "type": "boolean",
+            "description": "Indicates if the file is in the CMake installation"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "globsDependentV1_1": {
+      "type": "array",
+      "description": "Optional member present only when the project calls file(GLOB) or file(GLOB_RECURSE) with the CONFIGURE_DEPENDS option",
+      "items": {
+        "type": "object",
+        "required": [
+          "expression",
+          "paths"
+        ],
+        "properties": {
+          "expression": {
+            "type": "string",
+            "description": "The globbing expression. If the result of the expression no longer matches the same list of paths, the build system is considered out of date and the build tool will re-run cmake."
+          },
+          "recurse": {
+            "type": "boolean",
+            "description": "This will be true if the glob expression was from a file(GLOB_RECURSE) call"
+          },
+          "listDirectories": {
+            "type": "boolean",
+            "description": "This will be true if the expression is from a file(GLOB) that does not specify LIST_DIRECTORIES false, or from a file(GLOB_RECURSE) with LIST_DIRECTORIES set to true"
+          },
+          "followSymlinks": {
+            "type": "boolean",
+            "description": "This will be true if the FOLLOW_SYMLINKS option was given"
+          },
+          "relative": {
+            "type": "string",
+            "description": "This will be present if the RELATIVE option was given. The value is the path given after the RELATIVE keyword."
+          },
+          "paths": {
+            "type": "array",
+            "items": {
+              "type": "string"
+            },
+            "description": "Paths matched by the globbing expression"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "cmakeFilesV1_0": {
+      "properties": {
+        "kind": {
+          "$ref": "#/definitions/kind"
+        },
+        "version": {
+          "$ref": "#/definitions/versionV1_0"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "inputs": {
+          "$ref": "#/definitions/inputs"
+        }
+      },
+      "additionalProperties": false
+    },
+    "cmakeFilesV1_1": {
+      "properties": {
+        "kind": {
+          "$ref": "#/definitions/kind"
+        },
+        "version": {
+          "$ref": "#/definitions/versionV1_1"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "inputs": {
+          "$ref": "#/definitions/inputs"
+        },
+        "globsDependent": {
+          "$ref": "#/definitions/globsDependentV1_1"
+        }
+      },
+      "additionalProperties": false
+    }
+  }
+}
diff --git a/Help/manual/file_api/schema_codemodel.json b/Help/manual/file_api/schema_codemodel.json
new file mode 100644
index 0000000..4a5045e
--- /dev/null
+++ b/Help/manual/file_api/schema_codemodel.json
@@ -0,0 +1,390 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "description": "Schema for the CMake codemodel object kind",
+  "type": "object",
+  "required": [
+    "kind",
+    "version",
+    "paths",
+    "configurations"
+  ],
+  "oneOf": [
+    {
+      "$ref": "#/definitions/codemodelV2_0"
+    },
+    {
+      "$ref": "#/definitions/codemodelV2_3"
+    }
+  ],
+  "definitions": {
+    "kind": {
+      "type": "string",
+      "const": "codemodel",
+      "description": "Specifies the object kind"
+    },
+    "versionV2_0": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 2
+        },
+        "minor": {
+          "type": "integer",
+          "minimum": 0,
+          "maximum": 2
+        }
+      },
+      "additionalProperties": false
+    },
+    "versionV2_3": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 2
+        },
+        "minor": {
+          "type": "integer",
+          "minimum": 3
+        }
+      },
+      "additionalProperties": false
+    },
+    "paths": {
+      "type": "object",
+      "required": [
+        "source",
+        "build"
+      ],
+      "properties": {
+        "source": {
+          "type": "string",
+          "description": "Absolute path to the top-level source directory"
+        },
+        "build": {
+          "type": "string",
+          "description": "Absolute path to the top-level build directory"
+        }
+      },
+      "additionalProperties": false
+    },
+    "configurationDirectoryItemSource": {
+      "type": "string",
+      "description": "Path to the source directory. If it is inside the top level source directory, the path will be relative to that directory. For the top level source directory, this will simply be '.'. Paths outside the top level source directory will be absolute."
+    },
+    "configurationDirectoryItemBuild": {
+      "type": "string",
+      "description": "Path to the build directory. If it is inside the top level build directory, the path will be relative to that directory. For the top level build directory, this will simply be '.'. Paths outside the top level build directory will be absolute."
+    },
+    "configurationDirectoryItemParentIndex": {
+      "type": "integer",
+      "minimum": 0,
+      "description": "Index of the parent directory in the directories array"
+    },
+    "configurationDirectoryItemChildIndexes": {
+      "type": "array",
+      "items": {
+        "type": "integer",
+        "minimum": 0
+      },
+      "description": "Indices of child directories"
+    },
+    "configurationDirectoryItemProjectIndex": {
+      "type": "integer",
+      "minimum": 0,
+      "description": "Index into the projects array"
+    },
+    "configurationDirectoryItemTargetIndexes": {
+      "type": "array",
+      "items": {
+        "type": "integer",
+        "minimum": 0
+      },
+      "description": "Indices into the targets array"
+    },
+    "configurationDirectoryItemMinimumCMakeVersion": {
+      "type": "object",
+      "required": [
+        "string"
+      ],
+      "properties": {
+        "string": {
+          "type": "string",
+          "description": "Minimum required CMake version, if known"
+        }
+      },
+      "additionalProperties": false
+    },
+    "configurationDirectoryItemHasInstallRule": {
+      "type": "boolean",
+      "description": "Whether the directory has install rules"
+    },
+    "configurationDirectoryItemJsonFileV2_3": {
+      "jsonFile": {
+        "type": "string",
+        "description": "Path to directory-specific JSON file"
+      }
+    },
+    "configurationDirectoriesV2_0": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "source",
+          "build",
+          "projectIndex"
+        ],
+        "properties": {
+          "source": {
+            "$ref": "#/definitions/configurationDirectoryItemSource"
+          },
+          "build": {
+            "$ref": "#/definitions/configurationDirectoryItemBuild"
+          },
+          "parentIndex": {
+            "$ref": "#/definitions/configurationDirectoryItemParentIndex"
+          },
+          "childIndexes": {
+            "$ref": "#/definitions/configurationDirectoryItemChildIndexes"
+          },
+          "projectIndex": {
+            "$ref": "#/definitions/configurationDirectoryItemProjectIndex"
+          },
+          "targetIndexes": {
+            "$ref": "#/definitions/configurationDirectoryItemTargetIndexes"
+          },
+          "minimumCMakeVersion": {
+            "$ref": "#/definitions/configurationDirectoryItemMinimumCMakeVersion"
+          },
+          "hasInstallRule": {
+            "$ref": "#/definitions/configurationDirectoryItemHasInstallRule"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "configurationDirectoriesV2_3": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "source",
+          "build",
+          "projectIndex"
+        ],
+        "properties": {
+          "source": {
+            "$ref": "#/definitions/configurationDirectoryItemSource"
+          },
+          "build": {
+            "$ref": "#/definitions/configurationDirectoryItemBuild"
+          },
+          "parentIndex": {
+            "$ref": "#/definitions/configurationDirectoryItemParentIndex"
+          },
+          "childIndexes": {
+            "$ref": "#/definitions/configurationDirectoryItemChildIndexes"
+          },
+          "projectIndex": {
+            "$ref": "#/definitions/configurationDirectoryItemProjectIndex"
+          },
+          "targetIndexes": {
+            "$ref": "#/definitions/configurationDirectoryItemTargetIndexes"
+          },
+          "minimumCMakeVersion": {
+            "$ref": "#/definitions/configurationDirectoryItemMinimumCMakeVersion"
+          },
+          "hasInstallRule": {
+            "$ref": "#/definitions/configurationDirectoryItemHasInstallRule"
+          },
+          "jsonFile": {
+            "$ref": "#/definitions/configurationDirectoryItemJsonFileV2_3"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "configurationName": {
+      "type": "string",
+      "description": "Configuration name (e.g., 'Debug')"
+    },
+    "configurationProjects": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "name",
+          "directoryIndexes"
+        ],
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "Project name"
+          },
+          "parentIndex": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index of parent project"
+          },
+          "childIndexes": {
+            "type": "array",
+            "items": {
+              "type": "integer",
+              "minimum": 0
+            },
+            "description": "Indices of child projects"
+          },
+          "directoryIndexes": {
+            "type": "array",
+            "items": {
+              "type": "integer",
+              "minimum": 0
+            },
+            "description": "Indices into directories array"
+          },
+          "targetIndexes": {
+            "type": "array",
+            "items": {
+              "type": "integer",
+              "minimum": 0
+            },
+            "description": "Indices into targets array"
+          }
+        }
+      }
+    },
+    "configurationTargets": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "name",
+          "directoryIndex",
+          "projectIndex",
+          "jsonFile"
+        ],
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "Target name"
+          },
+          "id": {
+            "type": "string",
+            "description": "Unique target identifier"
+          },
+          "directoryIndex": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index into directories array"
+          },
+          "projectIndex": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index into projects array"
+          },
+          "jsonFile": {
+            "type": "string",
+            "description": "Path to target-specific JSON file"
+          }
+        }
+      }
+    },
+    "configurationsV2_0": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "name",
+          "directories",
+          "projects",
+          "targets"
+        ],
+        "properties": {
+          "name": {
+            "$ref": "#/definitions/configurationName"
+          },
+          "projects": {
+            "$ref": "#/definitions/configurationProjects"
+          },
+          "targets": {
+            "$ref": "#/definitions/configurationTargets"
+          },
+          "directories": {
+            "$ref": "#/definitions/configurationDirectoriesV2_0"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "configurationsV2_3": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "name",
+          "directories",
+          "projects",
+          "targets"
+        ],
+        "properties": {
+          "name": {
+            "$ref": "#/definitions/configurationName"
+          },
+          "projects": {
+            "$ref": "#/definitions/configurationProjects"
+          },
+          "targets": {
+            "$ref": "#/definitions/configurationTargets"
+          },
+          "directories": {
+            "$ref": "#/definitions/configurationDirectoriesV2_3"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "codemodelV2_0": {
+      "properties": {
+        "kind": {
+          "$ref": "#/definitions/kind"
+        },
+        "version": {
+          "$ref": "#/definitions/versionV2_0"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "configurations": {
+          "$ref": "#/definitions/configurationsV2_0"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_3": {
+      "properties": {
+        "kind": {
+          "$ref": "#/definitions/kind"
+        },
+        "version": {
+          "$ref": "#/definitions/versionV2_3"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "configurations": {
+          "$ref": "#/definitions/configurationsV2_3"
+        }
+      },
+      "additionalProperties": false
+    }
+  }
+}
diff --git a/Help/manual/file_api/schema_configureLog.json b/Help/manual/file_api/schema_configureLog.json
new file mode 100644
index 0000000..2f380b8
--- /dev/null
+++ b/Help/manual/file_api/schema_configureLog.json
@@ -0,0 +1,55 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "description": "Schema for the CMake configureLog object kind",
+  "type": "object",
+  "required": [
+    "kind",
+    "version",
+    "path",
+    "eventKindNames"
+  ],
+  "properties": {
+    "kind": {
+      "type": "string",
+      "const": "configureLog"
+    },
+    "version": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 1
+        },
+        "minor": {
+          "type": "integer",
+          "const": 0
+        }
+      },
+      "additionalProperties": false
+    },
+    "path": {
+      "type": "string",
+      "description": "Path to the configure log file. Clients must read the log file from this path, which may be different to the path in CMake's documentation. The log file specified by this path might not exist if no events have been logged."
+    },
+    "eventKindNames": {
+      "type": "array",
+      "description": "Names of versioned event kinds included in the configure log. Other event kinds might be present in the configure log, but clients must ignore those not listed in this array.",
+      "items": {
+        "type": "string",
+        "enum": [
+          "message-v1",
+          "try_compile-v1",
+          "try_run-v1",
+          "find-v1",
+          "find_package-v1"
+        ]
+      },
+      "uniqueItems": true
+    }
+  },
+  "additionalProperties": false
+}
diff --git a/Help/manual/file_api/schema_directory.json b/Help/manual/file_api/schema_directory.json
new file mode 100644
index 0000000..9b59229
--- /dev/null
+++ b/Help/manual/file_api/schema_directory.json
@@ -0,0 +1,636 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "description": "Schema for the CMake codemodel directory object",
+  "type": "object",
+  "oneOf": [
+    {
+      "$comment": "The top level codemodelVersion field was only added in version 2.9, so we can't differentiate between earlier versions",
+      "anyOf": [
+        {
+          "$ref": "#/definitions/codemodelV2_0"
+        },
+        {
+          "$ref": "#/definitions/codemodelV2_4"
+        },
+        {
+          "$ref": "#/definitions/codemodelV2_5"
+        }
+      ]
+    },
+    {
+      "$ref": "#/definitions/codemodelV2_9"
+    }
+  ],
+  "definitions": {
+    "codemodelVersionV2_9": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 2
+        },
+        "minor": {
+          "type": "integer",
+          "minimum": 9
+        }
+      },
+      "additionalProperties": false
+    },
+    "backtraceGraph": {
+      "type": "object",
+      "required": [
+        "nodes",
+        "commands",
+        "files"
+      ],
+      "properties": {
+        "nodes": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "required": [
+              "file"
+            ],
+            "properties": {
+              "file": {
+                "type": "integer",
+                "minimum": 0,
+                "description": "0-based index into the backtrace files array"
+              },
+              "line": {
+                "type": "integer",
+                "minimum": 1,
+                "description": "This is present when the node represents a line within the file. The line number is a 1-based value."
+              },
+              "command": {
+                "type": "integer",
+                "minimum": 0,
+                "description": "This is present when the node represents a command invocation. It is a 0-based index into the backtrace commands array."
+              },
+              "parent": {
+                "type": "integer",
+                "minimum": 0,
+                "description": "This is present when the node is not the bottom of the call stack. It is a 0-based index of another node in the backtrace nodes array."
+              }
+            },
+            "additionalProperties": false
+          }
+        },
+        "commands": {
+          "type": "array",
+          "description": "Each list item is a string specifying a command name",
+          "items": {
+            "type": "string"
+          }
+        },
+        "files": {
+          "type": "array",
+          "description": "Each list item is a string specifying the path to a file, represented with forward slashes. If the file is inside the top level source directory, the path is specified relative to that directory. Otherwise, the path is absolute.",
+          "items": {
+            "type": "string"
+          }
+        }
+      },
+      "additionalProperties": false
+    },
+    "paths": {
+      "type": "object",
+      "required": [
+        "source",
+        "build"
+      ],
+      "properties": {
+        "source": {
+          "type": "string",
+          "description": "Path to the source directory. If it is inside the top level source directory, the path will be relative to that directory. For the top level source directory, this will simply be '.'. Paths outside the top level source directory will be absolute."
+        },
+        "build": {
+          "type": "string",
+          "description": "Path to the build directory. If it is inside the top level build directory, the path will be relative to that directory. For the top level build directory, this will simply be '.'. Paths outside the top level build directory will be absolute."
+        }
+      },
+      "additionalProperties": false
+    },
+    "installerComponent": {
+      "type": "string",
+      "description": "Specifies the component selected by the corresponding install command invocation"
+    },
+    "installerDestination": {
+      "type": "string",
+      "description": "The install destination path. May be absolute or relative to the install prefix"
+    },
+    "installerPaths": {
+      "type": "array",
+      "description": "Paths (files or directories) to be installed",
+      "items": {
+        "oneOf": [
+          {
+            "type": "string",
+            "description": "Path from which a file/directory is installed, also specifying the install path"
+          },
+          {
+            "type": "object",
+            "properties": {
+              "from": {
+                "type": "string",
+                "description": "Path from which a file/directory is installed"
+              },
+              "to": {
+                "type": "string",
+                "description": "Path to which the file/directory is installed under the destination"
+              }
+            },
+            "required": [
+              "from",
+              "to"
+            ]
+          }
+        ]
+      }
+    },
+    "installerItemTypesV2_0": {
+      "type": "string",
+      "enum": [
+        "file",
+        "directory",
+        "target",
+        "export",
+        "script",
+        "code",
+        "importedRuntimeArtifacts",
+        "runtimeDependencySet"
+      ]
+    },
+    "installerItemTypesV2_4": {
+      "type": "string",
+      "enum": [
+        "fileSet"
+      ]
+    },
+    "installerItemTypesV2_5": {
+      "type": "string",
+      "enum": [
+        "cxxModuleBmi"
+      ]
+    },
+    "installerTypeV2_0": {
+      "$ref": "#/definitions/installerItemTypesV2_0",
+      "description": "Type of installation rule"
+    },
+    "installerTypeV2_4": {
+      "anyOf": [
+        {
+          "$ref": "#/definitions/installerItemTypesV2_0"
+        },
+        {
+          "$ref": "#/definitions/installerItemTypesV2_4"
+        }
+      ],
+      "description": "Type of installation rule"
+    },
+    "installerTypeV2_5": {
+      "anyOf": [
+        {
+          "$ref": "#/definitions/installerItemTypesV2_0"
+        },
+        {
+          "$ref": "#/definitions/installerItemTypesV2_4"
+        },
+        {
+          "$ref": "#/definitions/installerItemTypesV2_5"
+        }
+      ],
+      "description": "Type of installation rule"
+    },
+    "installerIsExcludeFromAll": {
+      "type": "boolean",
+      "description": "Present when install is called with EXCLUDE_FROM_ALL option"
+    },
+    "installerIsForAllComponents": {
+      "type": "boolean",
+      "description": "Present when install(SCRIPT|CODE) is called with ALL_COMPONENTS option"
+    },
+    "installerIsOptional": {
+      "type": "boolean",
+      "description": "Present when install is called with OPTIONAL option"
+    },
+    "installerTargetId": {
+      "type": "string",
+      "description": "Uniquely identifying string for the target to be installed"
+    },
+    "installerTargetIndex": {
+      "type": "integer",
+      "minimum": 0,
+      "description": "0-based index into the codemodel targets array"
+    },
+    "installerTargetIsImportLibrary": {
+      "type": "boolean",
+      "description": "Present for Windows DLL import library or AIX linker import file"
+    },
+    "installerTargetInstallNamelink": {
+      "type": "string",
+      "enum": [
+        "skip",
+        "only"
+      ],
+      "description": "How to handle symlinks for VERSION/SOVERSION target properties"
+    },
+    "installerExportName": {
+      "type": "string",
+      "description": "Name of the export for export type"
+    },
+    "installerExportTargets": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "string",
+            "description": "String uniquely identifying the target"
+          },
+          "index": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "0-based index into the codemodel targets array"
+          }
+        },
+        "additionalProperties": false,
+        "required": [
+          "id",
+          "index"
+        ]
+      }
+    },
+    "installerRuntimeDependencySetName": {
+      "type": "string",
+      "description": "Name of the runtime dependency set"
+    },
+    "installerRuntimeDependencySetType": {
+      "type": "string",
+      "enum": [
+        "library",
+        "framework"
+      ],
+      "description": "Type of runtime dependency set"
+    },
+    "installerScriptFile": {
+      "type": "string",
+      "description": "Path to the script file on disk"
+    },
+    "installerBacktrace": {
+      "type": "integer",
+      "minimum": 0,
+      "description": "0-based index into the backtraceGraph nodes array"
+    },
+    "installerFileSetNameV2_4": {
+      "type": "string",
+      "description": "Name of the file set"
+    },
+    "installerFileSetTypeV2_4": {
+      "type": "string",
+      "description": "Type of the file set"
+    },
+    "installerFileSetDirectoriesV2_4": {
+      "type": "array",
+      "items": {
+        "type": "string"
+      },
+      "description": "File set's base directories"
+    },
+    "installerFileSetTargetV2_4": {
+      "type": "object",
+      "required": [
+        "id",
+        "index"
+      ],
+      "properties": {
+        "id": {
+          "type": "string",
+          "description": "String uniquely identifying the target"
+        },
+        "index": {
+          "type": "integer",
+          "minimum": 0,
+          "description": "0-based index into the codemodel targets array"
+        }
+      },
+      "additionalProperties": false
+    },
+    "installerCxxModuleBmiTargetV2_5": {
+      "type": "object",
+      "properties": {
+        "id": {
+          "type": "string"
+        },
+        "index": {
+          "type": "integer",
+          "minimum": 0
+        }
+      },
+      "additionalProperties": false
+    },
+    "installersV2_0": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "component",
+          "type"
+        ],
+        "properties": {
+          "component": {
+            "$ref": "#/definitions/installerComponent"
+          },
+          "destination": {
+            "$ref": "#/definitions/installerDestination"
+          },
+          "paths": {
+            "$ref": "#/definitions/installerPaths"
+          },
+          "type": {
+            "$ref": "#/definitions/installerTypeV2_0"
+          },
+          "isExcludeFromAll": {
+            "$ref": "#/definitions/installerIsExcludeFromAll"
+          },
+          "isForAllComponents": {
+            "$ref": "#/definitions/installerIsForAllComponents"
+          },
+          "isOptional": {
+            "$ref": "#/definitions/installerIsOptional"
+          },
+          "targetId": {
+            "$ref": "#/definitions/installerTargetId"
+          },
+          "targetIndex": {
+            "$ref": "#/definitions/installerTargetIndex"
+          },
+          "targetIsImportLibrary": {
+            "$ref": "#/definitions/installerTargetIsImportLibrary"
+          },
+          "targetInstallNamelink": {
+            "$ref": "#/definitions/installerTargetInstallNamelink"
+          },
+          "exportName": {
+            "$ref": "#/definitions/installerExportName"
+          },
+          "exportTargets": {
+            "$ref": "#/definitions/installerExportTargets"
+          },
+          "runtimeDependencySetName": {
+            "$ref": "#/definitions/installerRuntimeDependencySetName"
+          },
+          "runtimeDependencySetType": {
+            "$ref": "#/definitions/installerRuntimeDependencySetType"
+          },
+          "scriptFile": {
+            "$ref": "#/definitions/installerScriptFile"
+          },
+          "backtrace": {
+            "$ref": "#/definitions/installerBacktrace"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "installersV2_4": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "component",
+          "type"
+        ],
+        "properties": {
+          "component": {
+            "$ref": "#/definitions/installerComponent"
+          },
+          "destination": {
+            "$ref": "#/definitions/installerDestination"
+          },
+          "paths": {
+            "$ref": "#/definitions/installerPaths"
+          },
+          "type": {
+            "$ref": "#/definitions/installerTypeV2_0"
+          },
+          "isExcludeFromAll": {
+            "$ref": "#/definitions/installerIsExcludeFromAll"
+          },
+          "isForAllComponents": {
+            "$ref": "#/definitions/installerIsForAllComponents"
+          },
+          "isOptional": {
+            "$ref": "#/definitions/installerIsOptional"
+          },
+          "targetId": {
+            "$ref": "#/definitions/installerTargetId"
+          },
+          "targetIndex": {
+            "$ref": "#/definitions/installerTargetIndex"
+          },
+          "targetIsImportLibrary": {
+            "$ref": "#/definitions/installerTargetIsImportLibrary"
+          },
+          "targetInstallNamelink": {
+            "$ref": "#/definitions/installerTargetInstallNamelink"
+          },
+          "exportName": {
+            "$ref": "#/definitions/installerExportName"
+          },
+          "exportTargets": {
+            "$ref": "#/definitions/installerExportTargets"
+          },
+          "runtimeDependencySetName": {
+            "$ref": "#/definitions/installerRuntimeDependencySetName"
+          },
+          "runtimeDependencySetType": {
+            "$ref": "#/definitions/installerRuntimeDependencySetType"
+          },
+          "scriptFile": {
+            "$ref": "#/definitions/installerScriptFile"
+          },
+          "backtrace": {
+            "$ref": "#/definitions/installerBacktrace"
+          },
+          "fileSetName": {
+            "$ref": "#/definitions/installerFileSetNameV2_4"
+          },
+          "fileSetType": {
+            "$ref": "#/definitions/installerFileSetTypeV2_4"
+          },
+          "fileSetDirectories": {
+            "$ref": "#/definitions/installerFileSetDirectoriesV2_4"
+          },
+          "fileSetTarget": {
+            "$ref": "#/definitions/installerFileSetTargetV2_4"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "installersV2_5": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "component",
+          "type"
+        ],
+        "properties": {
+          "component": {
+            "$ref": "#/definitions/installerComponent"
+          },
+          "destination": {
+            "$ref": "#/definitions/installerDestination"
+          },
+          "paths": {
+            "$ref": "#/definitions/installerPaths"
+          },
+          "type": {
+            "$ref": "#/definitions/installerTypeV2_5"
+          },
+          "isExcludeFromAll": {
+            "$ref": "#/definitions/installerIsExcludeFromAll"
+          },
+          "isForAllComponents": {
+            "$ref": "#/definitions/installerIsForAllComponents"
+          },
+          "isOptional": {
+            "$ref": "#/definitions/installerIsOptional"
+          },
+          "targetId": {
+            "$ref": "#/definitions/installerTargetId"
+          },
+          "targetIndex": {
+            "$ref": "#/definitions/installerTargetIndex"
+          },
+          "targetIsImportLibrary": {
+            "$ref": "#/definitions/installerTargetIsImportLibrary"
+          },
+          "targetInstallNamelink": {
+            "$ref": "#/definitions/installerTargetInstallNamelink"
+          },
+          "exportName": {
+            "$ref": "#/definitions/installerExportName"
+          },
+          "exportTargets": {
+            "$ref": "#/definitions/installerExportTargets"
+          },
+          "runtimeDependencySetName": {
+            "$ref": "#/definitions/installerRuntimeDependencySetName"
+          },
+          "runtimeDependencySetType": {
+            "$ref": "#/definitions/installerRuntimeDependencySetType"
+          },
+          "scriptFile": {
+            "$ref": "#/definitions/installerScriptFile"
+          },
+          "backtrace": {
+            "$ref": "#/definitions/installerBacktrace"
+          },
+          "fileSetName": {
+            "$ref": "#/definitions/installerFileSetNameV2_4"
+          },
+          "fileSetType": {
+            "$ref": "#/definitions/installerFileSetTypeV2_4"
+          },
+          "fileSetDirectories": {
+            "$ref": "#/definitions/installerFileSetDirectoriesV2_4"
+          },
+          "fileSetTarget": {
+            "$ref": "#/definitions/installerFileSetTargetV2_4"
+          },
+          "cxxModuleBmiTarget": {
+            "$ref": "#/definitions/installerCxxModuleBmiTargetV2_5"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "codemodelV2_0": {
+      "required": [
+        "backtraceGraph",
+        "paths",
+        "installers"
+      ],
+      "properties": {
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "installers": {
+          "$ref": "#/definitions/installersV2_0"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_4": {
+      "required": [
+        "backtraceGraph",
+        "paths",
+        "installers"
+      ],
+      "properties": {
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "installers": {
+          "$ref": "#/definitions/installersV2_4"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_5": {
+      "required": [
+        "backtraceGraph",
+        "paths",
+        "installers"
+      ],
+      "properties": {
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "installers": {
+          "$ref": "#/definitions/installersV2_5"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_9": {
+      "required": [
+        "codemodelVersion",
+        "backtraceGraph",
+        "paths",
+        "installers"
+      ],
+      "properties": {
+        "codemodelVersion": {
+          "$ref": "#/definitions/codemodelVersionV2_9"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "installers": {
+          "$ref": "#/definitions/installersV2_5"
+        }
+      },
+      "additionalProperties": false
+    }
+  }
+}
diff --git a/Help/manual/file_api/schema_index.json b/Help/manual/file_api/schema_index.json
new file mode 100644
index 0000000..a49ba1a
--- /dev/null
+++ b/Help/manual/file_api/schema_index.json
@@ -0,0 +1,248 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "type": "object",
+  "required": [
+    "cmake",
+    "objects",
+    "reply"
+  ],
+  "properties": {
+    "cmake": {
+      "type": "object",
+      "description": "High level details about CMake itself and the CMake generator used",
+      "required": [
+        "version",
+        "paths",
+        "generator"
+      ],
+      "properties": {
+        "version": {
+          "description": "Full version details of the CMake used to produce the replies",
+          "type": "object",
+          "required": [
+            "major",
+            "minor",
+            "patch",
+            "string",
+            "isDirty"
+          ],
+          "properties": {
+            "major": {
+              "type": "integer",
+              "minimum": 3
+            },
+            "minor": {
+              "type": "integer",
+              "minimum": 0
+            },
+            "patch": {
+              "type": "integer",
+              "minimum": 0
+            },
+            "suffix": {
+              "type": "string",
+              "description": "A version suffix may be present when CMake is built from sources, or for release candidates. Official releases do not normally have a suffix."
+            },
+            "string": {
+              "type": "string",
+              "description": "The full version string in the format <major>.<minor>.<patch>[-<suffix>]"
+            },
+            "isDirty": {
+              "type": "boolean",
+              "description": "When this is true, it indicates CMake was built from a version-controlled source tree with local modifications"
+            }
+          },
+          "additionalProperties": false
+        },
+        "paths": {
+          "description": "Absolute paths to tools and locations within the CMake installation",
+          "type": "object",
+          "required": [
+            "cmake",
+            "ctest",
+            "cpack",
+            "root"
+          ],
+          "properties": {
+            "cmake": {
+              "description": "Absolute path to the cmake executable",
+              "type": "string"
+            },
+            "ctest": {
+              "description": "Absolute path to the ctest executable",
+              "type": "string"
+            },
+            "cpack": {
+              "description": "Absolute path to the cpack executable",
+              "type": "string"
+            },
+            "root": {
+              "description": "Absolute path to the directory containing CMake resources like the Modules directory",
+              "type": "string"
+            }
+          },
+          "additionalProperties": false
+        },
+        "generator": {
+          "description": "Details for the CMake generator used",
+          "type": "object",
+          "required": [
+            "multiConfig",
+            "name"
+          ],
+          "properties": {
+            "multiConfig": {
+              "description": "True for multi-configuration generators, false for single-configuration generators",
+              "type": "boolean"
+            },
+            "name": {
+              "type": "string"
+            },
+            "platform": {
+              "description": "This string will only be set if the generator supports the CMAKE_GENERATOR_PLATFORM variable, which specifies the generator platform name",
+              "type": "string"
+            }
+          },
+          "additionalProperties": false
+        }
+      }
+    },
+    "objects": {
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/kindJsonFile"
+      }
+    },
+    "reply": {
+      "type": "object",
+      "patternProperties": {
+        "^[^-]+-v\\d+$": {
+          "description": "A member of this form appears for each of the shared stateless query files that CMake recognized as a request for the specified object kind and major version",
+          "oneOf": [
+            {
+              "$ref": "#/definitions/kindJsonFile"
+            },
+            {
+              "description": "A member of this form appears if the query's object kind is not recognized or is malformed",
+              "$ref": "#/definitions/replyError"
+            }
+          ]
+        },
+        "^client-[^/]+$": {
+          "description": "A member of this form appears for each client-owned directory holding client stateless query files. The value is a JSON object mirroring the content of the query/client-<client>/ directory.",
+          "patternProperties": {
+            "^[^-]+-v\\d+$": {
+              "description": "A member of this form appears for each of the client stateless query files that CMake recognized as a request for the specified object kind and major version",
+              "oneOf": [
+                {
+                  "$ref": "#/definitions/kindJsonFile"
+                },
+                {
+                  "description": "A member of this form appears if the client query's object kind is not recognized or is malformed",
+                  "$ref": "#/definitions/replyError"
+                }
+              ]
+            },
+            "^query\\.json$": {
+              "description": "This member appears for clients using client stateful query files",
+              "oneOf": [
+                {
+                  "type": "object",
+                  "properties": {
+                    "client": {
+                      "type": "object"
+                    },
+                    "requests": {},
+                    "responses": {
+                      "oneOf": [
+                        {
+                          "$ref": "#/definitions/replyError"
+                        },
+                        {
+                          "type": "array",
+                          "items": {
+                            "oneOf": [
+                              {
+                                "$ref": "#/definitions/kindJsonFile"
+                              },
+                              {
+                                "$ref": "#/definitions/replyError"
+                              }
+                            ]
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  "additionalProperties": false
+                },
+                {
+                  "description": "A member of this form appears if the query.json file failed to read or parse as a JSON object",
+                  "$ref": "#/definitions/replyError"
+                }
+              ]
+            }
+          },
+          "additionalProperties": {
+            "description": "A member of this form appears for each of the client stateless query files that CMake did not recognize.",
+            "$ref": "#/definitions/replyError"
+          }
+        }
+      },
+      "additionalProperties": {
+        "description": "A member of this form appears for each of the shared stateless query files that CMake did not recognize.",
+        "$ref": "#/definitions/replyError"
+      }
+    }
+  },
+  "definitions": {
+    "kindJsonFile": {
+      "type": "object",
+      "required": [
+        "kind",
+        "version",
+        "jsonFile"
+      ],
+      "properties": {
+        "kind": {
+          "type": "string"
+        },
+        "version": {
+          "type": "object",
+          "required": [
+            "major",
+            "minor"
+          ],
+          "properties": {
+            "major": {
+              "type": "integer",
+              "minimum": 1
+            },
+            "minor": {
+              "type": "integer",
+              "minimum": 0
+            }
+          },
+          "additionalProperties": false
+        },
+        "jsonFile": {
+          "type": "string",
+          "description": "Specifies a path relative to the reply index file to another JSON file containing the object"
+        }
+      },
+      "additionalProperties": false
+    },
+    "replyError": {
+      "type": "object",
+      "required": [
+        "error"
+      ],
+      "properties": {
+        "error": {
+          "type": "string"
+        }
+      },
+      "additionalProperties": false
+    }
+  }
+}
diff --git a/Help/manual/file_api/schema_stateful_query.json b/Help/manual/file_api/schema_stateful_query.json
new file mode 100644
index 0000000..fc3c251
--- /dev/null
+++ b/Help/manual/file_api/schema_stateful_query.json
@@ -0,0 +1,84 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "description": "Schema for CMake file API query.json files",
+  "type": "object",
+  "required": [
+    "requests"
+  ],
+  "properties": {
+    "requests": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "kind",
+          "version"
+        ],
+        "properties": {
+          "kind": {
+            "type": "string",
+            "description": "Specifies one of the Object Kinds to be included in the reply"
+          },
+          "version": {
+            "description": "Version(s) of the object kind that the client understands",
+            "oneOf": [
+              {
+                "$ref": "#/definitions/versionMajorOnly"
+              },
+              {
+                "$ref": "#/definitions/versionObject"
+              },
+              {
+                "type": "array",
+                "items": {
+                  "oneOf": [
+                    {
+                      "$ref": "#/definitions/versionMajorOnly"
+                    },
+                    {
+                      "$ref": "#/definitions/versionObject"
+                    }
+                  ]
+                }
+              }
+            ]
+          },
+          "client": {
+            "description": "Optional member reserved for use by the client. This value is preserved in the reply."
+          }
+        }
+      }
+    },
+    "client": {
+      "description": "Optional member reserved for use by the client. This value is preserved in the reply."
+    }
+  },
+  "$comment": "Other top level properties are reserved for future use. If present, they are ignored for forward compatibility.",
+  "additionalProperties": true,
+  "definitions": {
+    "versionMajorOnly": {
+      "type": "integer",
+      "description": "A non-negative major version number",
+      "minimum": 0
+    },
+    "versionObject": {
+      "type": "object",
+      "required": [
+        "major"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "description": "The major version number",
+          "minimum": 0
+        },
+        "minor": {
+          "type": "integer",
+          "description": "The minor version number",
+          "minimum": 0
+        }
+      },
+      "additionalProperties": false
+    }
+  }
+}
diff --git a/Help/manual/file_api/schema_target.json b/Help/manual/file_api/schema_target.json
new file mode 100644
index 0000000..0f3cff5
--- /dev/null
+++ b/Help/manual/file_api/schema_target.json
@@ -0,0 +1,1398 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "description": "Schema for the CMake codemodel target object",
+  "type": "object",
+  "oneOf": [
+    {
+      "$comment": "The top level codemodelVersion field was only added in version 2.9, so we can't differentiate between earlier versions",
+      "anyOf": [
+        {
+          "$ref": "#/definitions/codemodelV2_0"
+        },
+        {
+          "$ref": "#/definitions/codemodelV2_1"
+        },
+        {
+          "$ref": "#/definitions/codemodelV2_2"
+        },
+        {
+          "$ref": "#/definitions/codemodelV2_5"
+        },
+        {
+          "$ref": "#/definitions/codemodelV2_6"
+        },
+        {
+          "$ref": "#/definitions/codemodelV2_7"
+        },
+        {
+          "$ref": "#/definitions/codemodelV2_8"
+        }
+      ]
+    },
+    {
+      "$ref": "#/definitions/codemodelV2_9"
+    }
+  ],
+  "definitions": {
+    "codemodelVersionV2_9": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 2
+        },
+        "minor": {
+          "type": "integer",
+          "minimum": 9
+        }
+      },
+      "additionalProperties": false
+    },
+    "name": {
+      "type": "string",
+      "description": "Logical name of the target"
+    },
+    "id": {
+      "type": "string",
+      "description": "Unique identifier for the target. The format is unspecified and should not be interpreted by clients."
+    },
+    "type": {
+      "type": "string",
+      "enum": [
+        "EXECUTABLE",
+        "STATIC_LIBRARY",
+        "SHARED_LIBRARY",
+        "MODULE_LIBRARY",
+        "OBJECT_LIBRARY",
+        "INTERFACE_LIBRARY",
+        "UTILITY"
+      ]
+    },
+    "backtrace": {
+      "type": "integer",
+      "minimum": 0,
+      "description": "Index into backtraceGraph nodes array"
+    },
+    "folder": {
+      "type": "object",
+      "description": "This will only be present if the FOLDER target property is set",
+      "required": [
+        "name"
+      ],
+      "properties": {
+        "name": {
+          "type": "string",
+          "description": "Name of the folder to place the target under in IDEs and other GUI tools"
+        }
+      },
+      "additionalProperties": false
+    },
+    "paths": {
+      "type": "object",
+      "required": [
+        "source",
+        "build"
+      ],
+      "properties": {
+        "source": {
+          "type": "string",
+          "description": "Path to the source directory. If it is inside the top level source directory, the path will be relative to that directory. For the top level source directory, this will simply be '.'. Paths outside the top level source directory will be absolute."
+        },
+        "build": {
+          "type": "string",
+          "description": "Path to the build directory. If it is inside the top level build directory, the path will be relative to that directory. For the top level build directory, this will simply be '.'. Paths outside the top level build directory will be absolute."
+        }
+      },
+      "additionalProperties": false
+    },
+    "nameOnDisk": {
+      "type": "string",
+      "description": "File name of the primary artifact on disk, only present for executable and library targets that are linked or archived into a single primary artifact"
+    },
+    "artifacts": {
+      "type": "array",
+      "description": "Only present for executable and library targets that produce artifacts on disk meant for consumption by dependents",
+      "items": {
+        "type": "object",
+        "required": [
+          "path"
+        ],
+        "properties": {
+          "path": {
+            "type": "string",
+            "description": "Path to artifact file on disk. If the file is inside the top-level build directory, the path is specified relative to that directory. Otherwise, the path is absolute."
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "isGeneratorProvided": {
+      "type": "boolean",
+      "description": "Only present and will have the value true if the target is provided by CMake's build system generator rather than by a command in the project's source code"
+    },
+    "install": {
+      "type": "object",
+      "description": "Only present if the target has an install() rule",
+      "required": [
+        "prefix",
+        "destinations"
+      ],
+      "properties": {
+        "prefix": {
+          "type": "object",
+          "required": [
+            "path"
+          ],
+          "properties": {
+            "path": {
+              "type": "string",
+              "description": "The value of CMAKE_INSTALL_PREFIX"
+            }
+          },
+          "additionalProperties": false
+        },
+        "destinations": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "required": [
+              "path"
+            ],
+            "properties": {
+              "path": {
+                "type": "string",
+                "description": "Install destination path. It may be absolute or relative to the install prefix."
+              },
+              "backtrace": {
+                "type": "integer",
+                "minimum": 0,
+                "description": "Index into the backtraceGraph nodes array, if a backtrace is available"
+              }
+            },
+            "additionalProperties": false
+          }
+        }
+      },
+      "additionalProperties": false
+    },
+    "launchersV2_7": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "command",
+          "type"
+        ],
+        "properties": {
+          "command": {
+            "type": "string",
+            "description": "Path to the launcher on disk. If the file is inside the top-level source directory, the path is specified relative to that directory."
+          },
+          "arguments": {
+            "type": "array",
+            "items": {
+              "type": "string"
+            },
+            "description": "Arguments preceding the executable"
+          },
+          "type": {
+            "type": "string",
+            "enum": [
+              "emulator",
+              "test"
+            ],
+            "description": "Type of launcher"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "link": {
+      "type": "object",
+      "description": "This is only present for executables and shared library targets that link into a runtime binary",
+      "required": [
+        "language"
+      ],
+      "properties": {
+        "language": {
+          "type": "string",
+          "description": "Language of the toolchain used to invoke the linker"
+        },
+        "commandFragments": {
+          "type": "array",
+          "description": "Ordered fragments of the link command line, if available",
+          "items": {
+            "type": "object",
+            "required": [
+              "fragment",
+              "role"
+            ],
+            "properties": {
+              "fragment": {
+                "type": "string",
+                "description": "Fragment of link command line"
+              },
+              "role": {
+                "type": "string",
+                "enum": [
+                  "flags",
+                  "libraries",
+                  "libraryPath",
+                  "frameworkPath"
+                ],
+                "description": "Role of the fragment content"
+              },
+              "backtrace": {
+                "type": "integer",
+                "minimum": 0,
+                "description": "Index into backtraceGraph nodes array for the command that added the link fragment, if available"
+              }
+            },
+            "additionalProperties": false
+          }
+        },
+        "lto": {
+          "type": "boolean",
+          "description": "True if link-time optimization is enabled"
+        },
+        "sysroot": {
+          "type": "object",
+          "description": "Only present when the CMAKE_SYSROOT_LINK or CMAKE_SYSROOT variable is defined",
+          "required": [
+            "path"
+          ],
+          "properties": {
+            "path": {
+              "type": "string",
+              "description": "Absolute path to the sysroot"
+            }
+          },
+          "additionalProperties": false
+        }
+      },
+      "additionalProperties": false
+    },
+    "archive": {
+      "type": "object",
+      "description": "Only present for static library targets",
+      "properties": {
+        "commandFragments": {
+          "type": "array",
+          "description": "Ordered fragments of the archiver command line, if available",
+          "items": {
+            "type": "object",
+            "required": [
+              "fragment",
+              "role"
+            ],
+            "properties": {
+              "fragment": {
+                "type": "string",
+                "description": "Fragment of the archiver command line"
+              },
+              "role": {
+                "type": "string",
+                "enum": [
+                  "flags"
+                ],
+                "description": "Role of the fragment content"
+              }
+            },
+            "additionalProperties": false
+          }
+        },
+        "lto": {
+          "type": "boolean",
+          "description": "True if link-time optimization is enabled"
+        }
+      },
+      "additionalProperties": false
+    },
+    "debuggerV2_8": {
+      "type": "object",
+      "properties": {
+        "workingDirectory": {
+          "type": "string",
+          "description": "Working directory for a debugger"
+        }
+      },
+      "additionalProperties": false
+    },
+    "dependencies": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "id"
+        ],
+        "properties": {
+          "id": {
+            "type": "string",
+            "description": "Unique identifier of another target on which this one depends"
+          },
+          "backtrace": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index into backtraceGraph nodes array of the command that created the dependency, if available"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "fileSetsV2_5": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "name",
+          "type",
+          "visibility",
+          "baseDirectories"
+        ],
+        "properties": {
+          "name": {
+            "type": "string"
+          },
+          "type": {
+            "type": "string",
+            "enum": [
+              "HEADERS",
+              "CXX_MODULES"
+            ]
+          },
+          "visibility": {
+            "type": "string",
+            "enum": [
+              "PUBLIC",
+              "PRIVATE",
+              "INTERFACE"
+            ]
+          },
+          "baseDirectories": {
+            "type": "array",
+            "minItems": 1,
+            "items": {
+              "type": "string"
+            },
+            "description": "Base directories containing the file set's files. If a directory is inside the top level source directory, its path is specified relative to that directory. Otherwise, its path is absolute."
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "sourcesPath": {
+      "type": "string",
+      "description": "Path to the source file. If the file is inside the top level source directory, the path is specified relative to that directory. Otherwise, the path is absolute."
+    },
+    "sourcesCompileGroupIndex": {
+      "type": "integer",
+      "minimum": 0,
+      "description": "Index into the compileGroups array. Only present if the file is compiled."
+    },
+    "sourcesSourceGroupIndex": {
+      "type": "integer",
+      "minimum": 0,
+      "description": "Index into the sourceGroups array. Only present if the file is part of a source group."
+    },
+    "sourcesIsGenerated": {
+      "type": "boolean",
+      "description": "True if the file has its GENERATED property set to true"
+    },
+    "sourcesFileSetIndexV2_5": {
+      "type": "integer",
+      "minimum": 0,
+      "description": "Index into the fileSets array. Only present if the file is part of a file set."
+    },
+    "sourcesV2_0": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "path"
+        ],
+        "properties": {
+          "path": {
+            "$ref": "#/definitions/sourcesPath"
+          },
+          "compileGroupIndex": {
+            "$ref": "#/definitions/sourcesCompileGroupIndex"
+          },
+          "sourceGroupIndex": {
+            "$ref": "#/definitions/sourcesSourceGroupIndex"
+          },
+          "isGenerated": {
+            "$ref": "#/definitions/sourcesIsGenerated"
+          },
+          "backtrace": {
+            "$ref": "#/definitions/backtrace"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "sourcesV2_5": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "path"
+        ],
+        "properties": {
+          "path": {
+            "$ref": "#/definitions/sourcesPath"
+          },
+          "compileGroupIndex": {
+            "$ref": "#/definitions/sourcesCompileGroupIndex"
+          },
+          "sourceGroupIndex": {
+            "$ref": "#/definitions/sourcesSourceGroupIndex"
+          },
+          "isGenerated": {
+            "$ref": "#/definitions/sourcesIsGenerated"
+          },
+          "backtrace": {
+            "$ref": "#/definitions/backtrace"
+          },
+          "fileSetIndex": {
+            "$ref": "#/definitions/sourcesFileSetIndexV2_5"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "sourceGroups": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "name",
+          "sourceIndexes"
+        ],
+        "properties": {
+          "name": {
+            "type": "string",
+            "description": "Name of source group"
+          },
+          "sourceIndexes": {
+            "type": "array",
+            "items": {
+              "type": "integer",
+              "minimum": 0
+            },
+            "description": "Indices into sources array"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsSourceIndexes": {
+      "type": "array",
+      "items": {
+        "type": "integer",
+        "minimum": 0
+      },
+      "description": "Indices into the sources array for sources belonging to the group"
+    },
+    "compileGroupsLanguage": {
+      "type": "string",
+      "description": "Language used to compile sources in the group"
+    },
+    "compileGroupsLanguageStandardV2_2": {
+      "type": "object",
+      "required": [
+        "backtraces",
+        "standard"
+      ],
+      "properties": {
+        "backtraces": {
+          "type": "array",
+          "items": {
+            "type": "integer",
+            "minimum": 0
+          },
+          "description": "Indices into the backtraceGraph nodes array"
+        },
+        "standard": {
+          "type": "string",
+          "description": "Language standard"
+        }
+      },
+      "additionalProperties": false
+    },
+    "compileGroupsCompileCommandFragments": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "fragment"
+        ],
+        "properties": {
+          "fragment": {
+            "type": "string",
+            "description": "Fragment of the compile command line"
+          },
+          "backtrace": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index into the backtraceGraph nodes array"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsIncludes": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "path"
+        ],
+        "properties": {
+          "path": {
+            "type": "string",
+            "description": "Include directory path"
+          },
+          "isSystem": {
+            "type": "boolean",
+            "description": "True if the path is a system include directory"
+          },
+          "backtrace": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index into the backtraceGraph nodes array"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsFrameworksV2_6": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "path"
+        ],
+        "properties": {
+          "path": {
+            "type": "string",
+            "description": "Framework directory path"
+          },
+          "isSystem": {
+            "type": "boolean",
+            "description": "True if the path is to a system framework directory"
+          },
+          "backtrace": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index into the backtraceGraph nodes array"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsPrecompileHeadersV2_1": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "header"
+        ],
+        "properties": {
+          "header": {
+            "type": "string",
+            "description": "Path to the precompile header file"
+          },
+          "backtrace": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index into the backtraceGraph nodes array"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsDefines": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "define"
+        ],
+        "properties": {
+          "define": {
+            "type": "string",
+            "description": "Preprocessor definition in name or name=value format"
+          },
+          "backtrace": {
+            "type": "integer",
+            "minimum": 0,
+            "description": "Index into the backtraceGraph nodes array"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsSysroot": {
+      "type": "object",
+      "required": [
+        "path"
+      ],
+      "properties": {
+        "path": {
+          "type": "string",
+          "description": "Absolute path to the sysroot"
+        }
+      },
+      "additionalProperties": false
+    },
+    "compileGroupsV2_0": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "sourceIndexes",
+          "language"
+        ],
+        "properties": {
+          "sourceIndexes": {
+            "$ref": "#/definitions/compileGroupsSourceIndexes"
+          },
+          "language": {
+            "$ref": "#/definitions/compileGroupsLanguage"
+          },
+          "compileCommandFragments": {
+            "$ref": "#/definitions/compileGroupsCompileCommandFragments"
+          },
+          "includes": {
+            "$ref": "#/definitions/compileGroupsIncludes"
+          },
+          "defines": {
+            "$ref": "#/definitions/compileGroupsDefines"
+          },
+          "sysroot": {
+            "$ref": "#/definitions/compileGroupsSysroot"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsV2_1": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "sourceIndexes",
+          "language"
+        ],
+        "properties": {
+          "sourceIndexes": {
+            "$ref": "#/definitions/compileGroupsSourceIndexes"
+          },
+          "language": {
+            "$ref": "#/definitions/compileGroupsLanguage"
+          },
+          "compileCommandFragments": {
+            "$ref": "#/definitions/compileGroupsCompileCommandFragments"
+          },
+          "includes": {
+            "$ref": "#/definitions/compileGroupsIncludes"
+          },
+          "precompileHeaders": {
+            "$ref": "#/definitions/compileGroupsPrecompileHeadersV2_1"
+          },
+          "defines": {
+            "$ref": "#/definitions/compileGroupsDefines"
+          },
+          "sysroot": {
+            "$ref": "#/definitions/compileGroupsSysroot"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsV2_2": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "sourceIndexes",
+          "language"
+        ],
+        "properties": {
+          "sourceIndexes": {
+            "$ref": "#/definitions/compileGroupsSourceIndexes"
+          },
+          "language": {
+            "$ref": "#/definitions/compileGroupsLanguage"
+          },
+          "languageStandard": {
+            "$ref": "#/definitions/compileGroupsLanguageStandardV2_2"
+          },
+          "compileCommandFragments": {
+            "$ref": "#/definitions/compileGroupsCompileCommandFragments"
+          },
+          "includes": {
+            "$ref": "#/definitions/compileGroupsIncludes"
+          },
+          "precompileHeaders": {
+            "$ref": "#/definitions/compileGroupsPrecompileHeadersV2_1"
+          },
+          "defines": {
+            "$ref": "#/definitions/compileGroupsDefines"
+          },
+          "sysroot": {
+            "$ref": "#/definitions/compileGroupsSysroot"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "compileGroupsV2_6": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "required": [
+          "sourceIndexes",
+          "language"
+        ],
+        "properties": {
+          "sourceIndexes": {
+            "$ref": "#/definitions/compileGroupsSourceIndexes"
+          },
+          "language": {
+            "$ref": "#/definitions/compileGroupsLanguage"
+          },
+          "languageStandard": {
+            "$ref": "#/definitions/compileGroupsLanguageStandardV2_2"
+          },
+          "compileCommandFragments": {
+            "$ref": "#/definitions/compileGroupsCompileCommandFragments"
+          },
+          "includes": {
+            "$ref": "#/definitions/compileGroupsIncludes"
+          },
+          "frameworks": {
+            "$ref": "#/definitions/compileGroupsFrameworksV2_6"
+          },
+          "precompileHeaders": {
+            "$ref": "#/definitions/compileGroupsPrecompileHeadersV2_1"
+          },
+          "defines": {
+            "$ref": "#/definitions/compileGroupsDefines"
+          },
+          "sysroot": {
+            "$ref": "#/definitions/compileGroupsSysroot"
+          }
+        },
+        "additionalProperties": false
+      }
+    },
+    "backtraceGraph": {
+      "type": "object",
+      "required": [
+        "nodes",
+        "commands",
+        "files"
+      ],
+      "properties": {
+        "nodes": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "required": [
+              "file"
+            ],
+            "properties": {
+              "file": {
+                "type": "integer",
+                "minimum": 0,
+                "description": "0-based index into the backtrace files array"
+              },
+              "line": {
+                "type": "integer",
+                "minimum": 1,
+                "description": "This is present when the node represents a line within the file. The line number is a 1-based value."
+              },
+              "command": {
+                "type": "integer",
+                "minimum": 0,
+                "description": "This is present when the node represents a command invocation. It is a 0-based index into the backtrace commands array."
+              },
+              "parent": {
+                "type": "integer",
+                "minimum": 0,
+                "description": "This is present when the node is not the bottom of the call stack. It is a 0-based index of another node in the backtrace nodes array."
+              }
+            },
+            "additionalProperties": false
+          }
+        },
+        "commands": {
+          "type": "array",
+          "description": "Each list item is a string specifying a command name",
+          "items": {
+            "type": "string"
+          }
+        },
+        "files": {
+          "type": "array",
+          "description": "Each list item is a string specifying the path to a file, represented with forward slashes. If the file is inside the top level source directory, the path is specified relative to that directory. Otherwise, the path is absolute.",
+          "items": {
+            "type": "string"
+          }
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_0": {
+      "required": [
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/type"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_0"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroups"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_0"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_1": {
+      "required": [
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/type"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_0"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroups"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_1"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_2": {
+      "required": [
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/type"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_0"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroups"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_2"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_5": {
+      "required": [
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/type"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "fileSets": {
+          "$ref": "#/definitions/fileSetsV2_5"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_5"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroups"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_2"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_6": {
+      "required": [
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/type"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "fileSets": {
+          "$ref": "#/definitions/fileSetsV2_5"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_5"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroups"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_6"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_7": {
+      "required": [
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/type"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "launchers": {
+          "$ref": "#/definitions/launchersV2_7"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "fileSets": {
+          "$ref": "#/definitions/fileSetsV2_5"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_5"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroups"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_6"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_8": {
+      "required": [
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/type"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "launchers": {
+          "$ref": "#/definitions/launchersV2_7"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "debugger": {
+          "$ref": "#/definitions/debuggerV2_8"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "fileSets": {
+          "$ref": "#/definitions/fileSetsV2_5"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_5"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroups"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_6"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    },
+    "codemodelV2_9": {
+      "required": [
+        "codemodelVersion",
+        "name",
+        "id",
+        "type",
+        "paths",
+        "sources",
+        "backtraceGraph"
+      ],
+      "properties": {
+        "codemodelVersion": {
+          "$ref": "#/definitions/codemodelVersionV2_9"
+        },
+        "name": {
+          "$ref": "#/definitions/name"
+        },
+        "id": {
+          "$ref": "#/definitions/id"
+        },
+        "type": {
+          "$ref": "#/definitions/type"
+        },
+        "backtrace": {
+          "$ref": "#/definitions/backtrace"
+        },
+        "folder": {
+          "$ref": "#/definitions/folder"
+        },
+        "paths": {
+          "$ref": "#/definitions/paths"
+        },
+        "nameOnDisk": {
+          "$ref": "#/definitions/nameOnDisk"
+        },
+        "artifacts": {
+          "$ref": "#/definitions/artifacts"
+        },
+        "isGeneratorProvided": {
+          "$ref": "#/definitions/isGeneratorProvided"
+        },
+        "install": {
+          "$ref": "#/definitions/install"
+        },
+        "launchers": {
+          "$ref": "#/definitions/launchersV2_7"
+        },
+        "link": {
+          "$ref": "#/definitions/link"
+        },
+        "archive": {
+          "$ref": "#/definitions/archive"
+        },
+        "debugger": {
+          "$ref": "#/definitions/debuggerV2_8"
+        },
+        "dependencies": {
+          "$ref": "#/definitions/dependencies"
+        },
+        "fileSets": {
+          "$ref": "#/definitions/fileSetsV2_5"
+        },
+        "sources": {
+          "$ref": "#/definitions/sourcesV2_5"
+        },
+        "sourceGroups": {
+          "$ref": "#/definitions/sourceGroups"
+        },
+        "compileGroups": {
+          "$ref": "#/definitions/compileGroupsV2_6"
+        },
+        "backtraceGraph": {
+          "$ref": "#/definitions/backtraceGraph"
+        }
+      },
+      "additionalProperties": false
+    }
+  }
+}
diff --git a/Help/manual/file_api/schema_toolchains.json b/Help/manual/file_api/schema_toolchains.json
new file mode 100644
index 0000000..8ac4f29
--- /dev/null
+++ b/Help/manual/file_api/schema_toolchains.json
@@ -0,0 +1,117 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "description": "Schema for the CMake toolchains object kind",
+  "type": "object",
+  "required": [
+    "kind",
+    "version",
+    "toolchains"
+  ],
+  "properties": {
+    "kind": {
+      "type": "string",
+      "const": "toolchains",
+      "description": "Specifies the object kind"
+    },
+    "version": {
+      "type": "object",
+      "required": [
+        "major",
+        "minor"
+      ],
+      "properties": {
+        "major": {
+          "type": "integer",
+          "const": 1
+        },
+        "minor": {
+          "type": "integer",
+          "const": 0
+        }
+      },
+      "additionalProperties": false
+    },
+    "toolchains": {
+      "type": "array",
+      "description": "Array of toolchain configurations per language",
+      "items": {
+        "type": "object",
+        "required": [
+          "language",
+          "compiler"
+        ],
+        "properties": {
+          "language": {
+            "type": "string",
+            "description": "Toolchain language identifier (e.g. C, CXX)"
+          },
+          "compiler": {
+            "type": "object",
+            "properties": {
+              "path": {
+                "type": "string",
+                "description": "Path to the compiler executable. This is present when the CMAKE_<LANG>_COMPILER variable is defined."
+              },
+              "id": {
+                "type": "string",
+                "description": "Compiler identifier (e.g. GNU, MSVC). This is present when the CMAKE_<LANG>_COMPILER_ID variable is defined."
+              },
+              "version": {
+                "type": "string",
+                "description": "Version of the compiler. This is present when the CMAKE_<LANG>_COMPILER_VERSION variable is defined."
+              },
+              "target": {
+                "type": "string",
+                "description": "Cross-compiling target of the compiler. This is present when the CMAKE_<LANG>_COMPILER_TARGET variable is defined."
+              },
+              "implicit": {
+                "type": "object",
+                "properties": {
+                  "includeDirectories": {
+                    "type": "array",
+                    "items": {
+                      "type": "string"
+                    },
+                    "description": "List of implicit include directories for the compiler. This is present when the CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES variable is defined."
+                  },
+                  "linkDirectories": {
+                    "type": "array",
+                    "items": {
+                      "type": "string"
+                    },
+                    "description": "List of implicit link directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_DIRECTORIES variable is defined."
+                  },
+                  "linkFrameworkDirectories": {
+                    "type": "array",
+                    "items": {
+                      "type": "string"
+                    },
+                    "description": "List of implicit link framework directories for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_FRAMEWORK_DIRECTORIES variable is defined."
+                  },
+                  "linkLibraries": {
+                    "type": "array",
+                    "items": {
+                      "type": "string"
+                    },
+                    "description": "List of implicit link libraries for the compiler front end. This is present when the CMAKE_<LANG>_IMPLICIT_LINK_LIBRARIES variable is defined."
+                  }
+                },
+                "additionalProperties": false
+              }
+            },
+            "additionalProperties": false
+          },
+          "sourceFileExtensions": {
+            "type": "array",
+            "items": {
+              "type": "string"
+            },
+            "description": "List of source file extensions (without leading dot) supported by this toolchain"
+          }
+        },
+        "additionalProperties": false
+      }
+    }
+  },
+  "additionalProperties": false
+}
diff --git a/Help/policy/CMP0183.rst b/Help/policy/CMP0183.rst
index 6804c3b..f2d6601 100644
--- a/Help/policy/CMP0183.rst
+++ b/Help/policy/CMP0183.rst
@@ -5,7 +5,7 @@
 
 :command:`add_feature_info` supports full :ref:`Condition Syntax`.
 
-The ``<enabled>`` parameter accepts a :ref:`semicolon-separated list <CMake
+The ``<condition>`` parameter accepts a :ref:`semicolon-separated list <CMake
 Language Lists>` of conditions.  CMake 3.31 and lower evaluate each
 ``condition`` as ``if(${condition})``, which does not properly handle
 conditions with nested paren groups.  CMake 4.0 and above instead prefer
diff --git a/Help/policy/CMP0198.rst b/Help/policy/CMP0198.rst
new file mode 100644
index 0000000..4e32e1c
--- /dev/null
+++ b/Help/policy/CMP0198.rst
@@ -0,0 +1,23 @@
+CMP0198
+-------
+
+.. versionadded:: 4.2
+
+:variable:`CMAKE_PARENT_LIST_FILE` is not defined in ``CMakeLists.txt``.
+
+CMake 4.1 and below defined ``CMAKE_PARENT_LIST_FILE`` when processing
+a ``CMakeLists.txt`` even though there is no parent file.  CMake 4.2
+and above prefer to not define ``CMAKE_PARENT_LIST_FILE``.  This policy
+provides compatibility for projects that accidentally relied on the
+old behavior.
+
+The ``OLD`` behavior for this policy is to set
+:variable:`CMAKE_PARENT_LIST_FILE` to :variable:`CMAKE_CURRENT_LIST_FILE`
+when processing a ``CMakeLists.txt``.  The ``NEW`` behavior for this policy
+is to not set :variable:`CMAKE_PARENT_LIST_FILE`.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.2
+.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst
diff --git a/Help/policy/CMP0199.rst b/Help/policy/CMP0199.rst
new file mode 100644
index 0000000..cef282a
--- /dev/null
+++ b/Help/policy/CMP0199.rst
@@ -0,0 +1,93 @@
+CMP0199
+-------
+
+.. versionadded:: 4.2
+
+:genex:`$<CONFIG:cfgs>` only matches the configuration of the consumed target.
+
+Historically, when a :genex:`$<CONFIG:cfgs>` generator expression appeared in
+the properties of an imported target, it would match (that is, evaluate to
+``1``) if any of the ``cfgs`` matched *any* of the following:
+
+1. The selected configuration of the imported target being consumed.
+
+2. The configuration of the consuming target.
+
+3. *Any* of the configurations in the :prop_tgt:`MAP_IMPORTED_CONFIG_<CONFIG>`
+   of the imported target being consumed
+   (where ``<CONFIG>`` is the configuration of the consuming target),
+   *whether or not such configurations are valid for the imported target*.
+
+This could result in expressions which are intended to be mutually exclusive
+being concurrently evaluated.  This would be especially problematic if the
+value of a compile definition is intended to be determined by the
+configuration, as this lack of exclusivity could result in redefinition.
+
+CMake 4.2 and above prefer to consider *only* the configuration of the imported
+target being consumed; that is, (1) in the above list.
+
+This policy provides compatibility with projects that rely on the historical
+behavior.  The ``OLD`` behavior for this policy is to retain the historic
+behavior as described above.  The ``NEW`` behavior is to consider only the
+configuration of the imported target being consumed.
+
+.. note::
+
+  This policy only applies to generator expressions being evaluated as part of
+  the usage requirements of imported targets which are not imported from |CPS|
+  packages.
+
+  For non-imported targets, both the historic and ongoing behavior is to
+  consider only the configuration of the consuming target.  (The selected
+  configuration of a non-imported target is always the active build
+  configuration, which is necessarily the same as the consuming target's
+  configuration.)
+
+  For targets imported from |CPS| packages, the ``NEW`` behavior is used,
+  regardless of the policy setting.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.2
+.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst
+
+Examples
+^^^^^^^^
+
+Consider the following imported libraries:
+
+.. code-block:: cmake
+
+  add_library(test1 INTERFACE IMPORTED)
+  set_target_properties(test1 PROPERTIES
+    IMPORTED_CONFIGURATIONS "DEBUG"
+    INTERFACE_COMPILE_DEFINITIONS
+      "$<$<CONFIG:debug>:DEBUG>;$<$<CONFIG:release>:RELEASE>"
+  )
+
+  add_library(test2 INTERFACE IMPORTED)
+  set_target_properties(test2 PROPERTIES
+    IMPORTED_CONFIGURATIONS "TEST"
+    INTERFACE_COMPILE_DEFINITIONS
+      "$<$<CONFIG:debug>:DEBUG>;$<$<CONFIG:example>:EXAMPLE>;$<$<CONFIG:test>:TEST>"
+    MAP_IMPORTED_CONFIG_RELEASE "DEBUG;EXAMPLE;TEST"
+  )
+
+Assume that the consuming project is built in the ``Release`` configuration.
+Under the ``OLD`` policy, a consumer of ``test1`` would see both ``DEBUG``
+and ``RELEASE`` defined; ``$<CONFIG:debug>`` evaluates to ``1`` because the
+selected configuration of ``test1`` is ``DEBUG``, and ``$<CONFIG:release>``
+evaluates to ``1`` because the consumer's configuration is ``Release``
+(keeping in mind that configuration matching is case-insensitive). Likewise,
+a consumer of ``test2`` would see all of ``DEBUG``, ``RELEASE`` and ``TEST``
+defined; ``$<CONFIG:debug>``, ``$<CONFIG:example>`` and ``$<CONFIG:test>`` all
+evaluate to ``1`` because all of these configurations appear in
+``MAP_IMPORTED_CONFIG_RELEASE``.
+
+Under the ``NEW`` policy, when ``test1`` is consumed, only ``$<CONFIG:debug>``
+will evaluate to ``1``. Similarly, when ``test2`` is consumed, only
+``$<CONFIG:test>`` will evaluate to ``1``. Both of these correspond to the
+configuration of the consumed library that is actually selected by CMake.
+
+.. |CPS| replace:: Common Package Specification
diff --git a/Help/prop_gbl/JOB_POOLS.rst b/Help/prop_gbl/JOB_POOLS.rst
index 5dfe6de..7d39d8b 100644
--- a/Help/prop_gbl/JOB_POOLS.rst
+++ b/Help/prop_gbl/JOB_POOLS.rst
@@ -14,15 +14,21 @@
 
   set_property(GLOBAL PROPERTY JOB_POOLS two_jobs=2 ten_jobs=10)
 
-Defined pools could be used globally by setting
-:variable:`CMAKE_JOB_POOL_COMPILE` and :variable:`CMAKE_JOB_POOL_LINK`
-or per target by setting the target properties
-:prop_tgt:`JOB_POOL_COMPILE` and :prop_tgt:`JOB_POOL_LINK`.
-:command:`Custom commands <add_custom_command>` and
-:command:`custom targets <add_custom_target>` can specify pools using the
-option ``JOB_POOL``.
-Using a pool that is not defined by ``JOB_POOLS`` causes
-an error by ninja at build time.
+Defined pools can be used at different levels:
+
+* Globally, by setting :variable:`CMAKE_JOB_POOL_COMPILE` and
+  :variable:`CMAKE_JOB_POOL_LINK`.
+* Per target, by setting the target properties :prop_tgt:`JOB_POOL_COMPILE`
+  and :prop_tgt:`JOB_POOL_LINK`.
+* :command:`Custom commands <add_custom_command>` and
+  :command:`custom targets <add_custom_target>` can specify pools using the
+  option ``JOB_POOL``.
+* Per-source, by setting the source file property :prop_sf:`JOB_POOL_COMPILE`,
+  in case some specific source files require to override their global or
+  target assigned pool.
+
+Using a pool that is not defined by ``JOB_POOLS`` causes an error by ninja
+at build time.
 
 If not set, this property uses the value of the :variable:`CMAKE_JOB_POOLS`
 variable.
diff --git a/Help/prop_sf/JOB_POOL_COMPILE.rst b/Help/prop_sf/JOB_POOL_COMPILE.rst
new file mode 100644
index 0000000..349a0b1
--- /dev/null
+++ b/Help/prop_sf/JOB_POOL_COMPILE.rst
@@ -0,0 +1,19 @@
+JOB_POOL_COMPILE
+----------------
+
+Ninja only: Pool used for compiling.
+
+The number of parallel compile processes could be limited by defining
+pools with the global :prop_gbl:`JOB_POOLS`
+property and then specifying here the pool name.
+
+This allows to override the :prop_tgt:`JOB_POOL_COMPILE`
+value for specific source files within a same target.
+
+For instance:
+
+.. code-block:: cmake
+
+  set_property(SOURCE main.cc PROPERTY JOB_POOL_COMPILE two_jobs)
+
+This property is undefined by default.
diff --git a/Help/prop_test/ENVIRONMENT_MODIFICATION.rst b/Help/prop_test/ENVIRONMENT_MODIFICATION.rst
index c6c1a82..cb9cfcd 100644
--- a/Help/prop_test/ENVIRONMENT_MODIFICATION.rst
+++ b/Help/prop_test/ENVIRONMENT_MODIFICATION.rst
@@ -13,26 +13,7 @@
 to be modified.  Entries are considered in the order specified in the
 property's value.  The ``OP`` may be one of:
 
-- ``reset``: Reset to the unmodified value, ignoring all modifications to
-  ``MYVAR`` prior to this entry. Note that this will reset the variable to
-  the value set by :prop_test:`ENVIRONMENT`, if it was set, and otherwise
-  to its state from the rest of the CTest execution.
-- ``set``: Replaces the current value of ``MYVAR`` with ``VALUE``.
-- ``unset``: Unsets the current value of ``MYVAR``.
-- ``string_append``: Appends singular ``VALUE`` to the current value of
-  ``MYVAR``.
-- ``string_prepend``: Prepends singular ``VALUE`` to the current value of
-  ``MYVAR``.
-- ``path_list_append``: Appends singular ``VALUE`` to the current value of
-  ``MYVAR`` using the host platform's path list separator (``;`` on Windows
-  and ``:`` elsewhere).
-- ``path_list_prepend``: Prepends singular ``VALUE`` to the current value of
-  ``MYVAR`` using the host platform's path list separator (``;`` on Windows
-  and ``:`` elsewhere).
-- ``cmake_list_append``: Appends singular ``VALUE`` to the current value of
-  ``MYVAR`` using ``;`` as the separator.
-- ``cmake_list_prepend``: Prepends singular ``VALUE`` to the current value of
-  ``MYVAR`` using ``;`` as the separator.
+ .. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
 
 Unrecognized ``OP`` values will result in the test failing before it is
 executed. This is so that future operations may be added without changing
diff --git a/Help/prop_tgt/COMPILE_PDB_NAME.rst b/Help/prop_tgt/COMPILE_PDB_NAME.rst
index 1b4657e..166cfc1 100644
--- a/Help/prop_tgt/COMPILE_PDB_NAME.rst
+++ b/Help/prop_tgt/COMPILE_PDB_NAME.rst
@@ -9,6 +9,9 @@
 This property specifies the base name for the debug symbols file.
 If not set, the default is unspecified.
 
+If the :prop_tgt:`PRECOMPILE_HEADERS_REUSE_FROM` target is set, this property
+is ignored and the reusage target's value of this property is used instead.
+
 .. versionadded:: 4.1
 
   Contents of ``COMPILE_PDB_NAME`` may use
diff --git a/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst
index f21bdc9..162011d 100644
--- a/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst
+++ b/Help/prop_tgt/COMPILE_PDB_NAME_CONFIG.rst
@@ -13,5 +13,8 @@
   Contents of ``COMPILE_PDB_NAME_<CONFIG>`` may use
   :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
+If the :prop_tgt:`PRECOMPILE_HEADERS_REUSE_FROM` target is set, this property
+is ignored and the reusage target's value of this property is used instead.
+
 .. |PDB_XXX| replace:: :prop_tgt:`PDB_NAME_<CONFIG>`
 .. include:: include/COMPILE_PDB_NOTE.rst
diff --git a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst
index 5bfb50b..9fa7ff2 100644
--- a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst
+++ b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY.rst
@@ -21,5 +21,8 @@
 :variable:`CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY` variable if it is
 set when a target is created.
 
+If the :prop_tgt:`PRECOMPILE_HEADERS_REUSE_FROM` target is set, this property
+is ignored and the reusage target's value of this property is used instead.
+
 .. |PDB_XXX| replace:: :prop_tgt:`PDB_OUTPUT_DIRECTORY`
 .. include:: include/COMPILE_PDB_NOTE.rst
diff --git a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
index c2d4a94..fc9121c 100644
--- a/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
+++ b/Help/prop_tgt/COMPILE_PDB_OUTPUT_DIRECTORY_CONFIG.rst
@@ -20,5 +20,8 @@
   Contents of ``COMPILE_PDB_OUTPUT_DIRECTORY_<CONFIG>`` may use
   :manual:`generator expressions <cmake-generator-expressions(7)>`.
 
+If the :prop_tgt:`PRECOMPILE_HEADERS_REUSE_FROM` target is set, this property
+is ignored and the reusage target's value of this property is used instead.
+
 .. |PDB_XXX| replace:: :prop_tgt:`PDB_OUTPUT_DIRECTORY_<CONFIG>`
 .. include:: include/COMPILE_PDB_NOTE.rst
diff --git a/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
index d09ff19..8a5c562 100644
--- a/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
+++ b/Help/prop_tgt/CROSSCOMPILING_EMULATOR.rst
@@ -20,3 +20,6 @@
 This property is initialized by the value of the
 :variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable if it is set when a target
 is created.
+
+This property is not supported when using the old form of :command:`add_test`
+(i.e. without the ``NAME`` and ``COMMAND`` keywords).
diff --git a/Help/prop_tgt/CXX_STANDARD.rst b/Help/prop_tgt/CXX_STANDARD.rst
index 9b381e4..177f12e 100644
--- a/Help/prop_tgt/CXX_STANDARD.rst
+++ b/Help/prop_tgt/CXX_STANDARD.rst
@@ -40,9 +40,6 @@
 ``26``
   .. versionadded:: 3.25
 
-  C++26. CMake 3.25 and later *recognize* ``26`` as a valid value,
-  no version has support for any compiler.
-
 If the value requested does not result in a compile flag being added for
 the compiler in use, a previous standard flag will be added instead.  This
 means that using:
diff --git a/Help/prop_tgt/EXPORT_FIND_PACKAGE_NAME.rst b/Help/prop_tgt/EXPORT_FIND_PACKAGE_NAME.rst
index b7405d6..f74f6d3 100644
--- a/Help/prop_tgt/EXPORT_FIND_PACKAGE_NAME.rst
+++ b/Help/prop_tgt/EXPORT_FIND_PACKAGE_NAME.rst
@@ -6,9 +6,10 @@
   Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES``.
 
 Control the package name associated with a dependency target when exporting a
-:command:`find_dependency` call in :command:`install(EXPORT)` or
+:command:`find_dependency` call in :command:`install(PACKAGE_INFO)`,
+:command:`export(PACKAGE_INFO)`, :command:`install(EXPORT)` or
 :command:`export(EXPORT)`. This can be used to assign a package name to a
-package that is built by CMake and exported, or to override the package in the
-:command:`find_package` call that created the target.
+package that is built by CMake and exported, or a package that was provided by
+:module:`FetchContent`.
 
 This property is initialized by :variable:`CMAKE_EXPORT_FIND_PACKAGE_NAME`.
diff --git a/Help/prop_tgt/POSITION_INDEPENDENT_CODE.rst b/Help/prop_tgt/POSITION_INDEPENDENT_CODE.rst
index 2ba1e6f..85e4cf6 100644
--- a/Help/prop_tgt/POSITION_INDEPENDENT_CODE.rst
+++ b/Help/prop_tgt/POSITION_INDEPENDENT_CODE.rst
@@ -1,10 +1,11 @@
 POSITION_INDEPENDENT_CODE
 -------------------------
 
-Whether to create a position-independent target
+A target property that specifies whether to create a target that has
+position-independent code enabled.
 
-The ``POSITION_INDEPENDENT_CODE`` property determines whether position
-independent executables or libraries will be created.  This
+The ``POSITION_INDEPENDENT_CODE`` target property determines whether
+position-independent executables or libraries will be created.  This
 property is ``True`` by default for ``SHARED`` and ``MODULE`` library
 targets.  For other targets, this property is initialized by the value
 of the :variable:`CMAKE_POSITION_INDEPENDENT_CODE` variable if it is set
@@ -14,3 +15,57 @@
 
   For executable targets, the link step is controlled by the :policy:`CMP0083`
   policy and the :module:`CheckPIESupported` module.
+
+Position-independent code (PIC) refers to machine code that executes
+properly regardless of its absolute memory address.  This is particularly
+important for shared libraries, which are often loaded at different memory
+addresses by different programs.  Generating position-independent code
+ensures that these libraries can be safely and efficiently shared among
+multiple processes without causing address conflicts.  On some platforms
+(notably UNIX-like systems), generating PIC is also a requirement for
+creating shared libraries.
+
+Use of position-independent code is recommended or required in the following
+cases:
+
+* When building shared or module libraries (e.g., with
+  ``add_library(... SHARED)``, or ``add_library(... MODULE)``), where PIC
+  allows dynamic relocation at runtime.
+
+* When building executables as position-independent executables (PIE), which
+  can enhance security by enabling Address Space Layout Randomization (ASLR).
+
+* On platforms or toolchains that require PIC for certain types of linking
+  or sandboxed environments.
+
+Enabling PIC can result in slightly larger or slower code on some
+architectures, but this is often outweighed by the benefits of flexibility
+and security.
+
+Examples
+^^^^^^^^
+
+Enabling PIC for a static library target:
+
+.. code-block:: cmake
+
+  add_library(foo STATIC foo.c)
+  set_target_properties(foo PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
+
+Enabling PIC for an executable target:
+
+.. code-block:: cmake
+
+  add_executable(app app.c)
+
+  set_target_properties(app PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
+
+  # Additionally, pass PIE-related link-time options to executable(s).
+  include(CheckPIESupported)
+  check_pie_supported()
+
+See Also
+^^^^^^^^
+
+* The :module:`CheckPIESupported` module to pass PIE-related options to the
+  linker for executables.
diff --git a/Help/prop_tgt/SPDX_LICENSE.rst b/Help/prop_tgt/SPDX_LICENSE.rst
index 056c860..a030e6c 100644
--- a/Help/prop_tgt/SPDX_LICENSE.rst
+++ b/Help/prop_tgt/SPDX_LICENSE.rst
@@ -3,9 +3,9 @@
 
 .. versionadded:: 4.1
 
-Specify the license of a target using a |SPDX|_ (SPDX) `License Expression`_.
-See the SPDX `License List`_ for a list of commonly used licenses and their
-identifiers.
+Specify the license(s) of a target using a |SPDX|_ (SPDX)
+`License Expression`_. See the SPDX `License List`_ for a list of commonly used
+licenses and their identifiers.
 
 .. _SPDX: https://spdx.dev/
 .. |SPDX| replace:: System Package Data Exchange
diff --git a/Help/prop_tgt/TEST_LAUNCHER.rst b/Help/prop_tgt/TEST_LAUNCHER.rst
index 7eec319..a2103bc 100644
--- a/Help/prop_tgt/TEST_LAUNCHER.rst
+++ b/Help/prop_tgt/TEST_LAUNCHER.rst
@@ -21,3 +21,6 @@
 This property is initialized by the value of the
 :variable:`CMAKE_TEST_LAUNCHER` variable if it is set when a target
 is created.
+
+This property is not supported when using the old form of :command:`add_test`
+(i.e. without the ``NAME`` and ``COMMAND`` keywords).
diff --git a/Help/release/3.14.rst b/Help/release/3.14.rst
index 6b3a187..8701474 100644
--- a/Help/release/3.14.rst
+++ b/Help/release/3.14.rst
@@ -346,6 +346,9 @@
   ``xmlrpc``.  CDash is the only maintained testing dashboard for CTest,
   and it only supports submissions over ``http`` and ``https``.
 
+* The :module:`MacroAddFileDependencies` module is deprecated.
+  Port projects to use :command:`set_property` directly.
+
 Other Changes
 =============
 
diff --git a/Help/release/3.16.rst b/Help/release/3.16.rst
index 28273a7..f9f9b33 100644
--- a/Help/release/3.16.rst
+++ b/Help/release/3.16.rst
@@ -165,7 +165,7 @@
   a new ``REASON_FAILURE_MESSAGE`` option to specify a message
   giving the reason for the failure.
 
-* The :module:`FindPkgConfig` module :command:`pkg_search_module` macro
+* The :module:`FindPkgConfig` module :command:`pkg_search_module` command
   now defines a ``<prefix>_MODULE_NAME`` result variable containing the
   first matching module name.
 
diff --git a/Help/release/3.22.rst b/Help/release/3.22.rst
index efc8115..fa57fc4 100644
--- a/Help/release/3.22.rst
+++ b/Help/release/3.22.rst
@@ -75,7 +75,7 @@
 
 * The :module:`FindMatlab` module now provides imported targets.
 
-* The :module:`FindPkgConfig` module gained a :variable:`PKG_CONFIG_ARGN`
+* The :module:`FindPkgConfig` module gained a ``PKG_CONFIG_ARGN``
   variable to specify arguments to ``pkg-config`` calls.
 
 * The :module:`GoogleTest` module :command:`gtest_discover_tests`
diff --git a/Help/release/3.3.rst b/Help/release/3.3.rst
index efb6a7c..3b1da25 100644
--- a/Help/release/3.3.rst
+++ b/Help/release/3.3.rst
@@ -135,7 +135,7 @@
   documentation, and unit tests.
 
 * The :module:`FindPackageHandleStandardArgs` module
-  ``find_package_handle_standard_args`` function now
+  :command:`find_package_handle_standard_args` command now
   always populates both the ``<PackageName>_FOUND``
   and ``<UPPERCASE_NAME>_FOUND`` variables (the latter
   for backwards compatibility).  The ``FOUND_VAR``
diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst
new file mode 100644
index 0000000..e4cc01e
--- /dev/null
+++ b/Help/release/dev/0-sample-topic.rst
@@ -0,0 +1,7 @@
+0-sample-topic
+--------------
+
+* This is a sample release note for the change in a topic.
+  Developers should add similar notes for each topic branch
+  making a noteworthy change.  Each document should be named
+  and titled to match the topic name to avoid merge conflicts.
diff --git a/Help/release/dev/FindDevIL.rst b/Help/release/dev/FindDevIL.rst
new file mode 100644
index 0000000..b94a933
--- /dev/null
+++ b/Help/release/dev/FindDevIL.rst
@@ -0,0 +1,6 @@
+FindDevIL
+---------
+
+* The :module:`FindDevIL` module now provides a ``DevIL_VERSION`` result
+  variable and version argument and version range can be specified by
+  :command:`find_package`, when finding the DevIL package.
diff --git a/Help/release/dev/GenEx-COMPILER_LINKER.rst b/Help/release/dev/GenEx-COMPILER_LINKER.rst
new file mode 100644
index 0000000..d0a1896
--- /dev/null
+++ b/Help/release/dev/GenEx-COMPILER_LINKER.rst
@@ -0,0 +1,8 @@
+GenEx-COMPILER_LINKER
+---------------------
+
+* The :genex:`<LANG>_COMPILER_LINKER_ID <C_COMPILER_LINKER_ID>` and
+  :genex:`<LANG>_COMPILER_LINKER_FRONTEND_VARIANT <C_COMPILER_LINKER_FRONTEND_VARIANT>`
+  families of generator expressions were added to access the value of the
+  associated :variable:`CMAKE_<LANG>_COMPILER_LINKER_ID` and
+  :variable:`CMAKE_<LANG>_COMPILER_LINKER_FRONTEND_VARIANT` variables.
diff --git a/Help/release/dev/cmake-copy-if-newer.rst b/Help/release/dev/cmake-copy-if-newer.rst
new file mode 100644
index 0000000..e9a857c
--- /dev/null
+++ b/Help/release/dev/cmake-copy-if-newer.rst
@@ -0,0 +1,9 @@
+cmake-copy-if-newer
+-------------------
+
+* The :manual:`cmake(1)` command-line tool now supports
+  ``cmake -E copy_if_newer`` and ``cmake -E copy_directory_if_newer``
+  subcommands to copy files based on timestamp comparison instead of
+  content comparison. These commands copy files only if the source is
+  newer than the destination, providing better performance for build
+  systems compared to ``copy_if_different`` which compares file contents.
diff --git a/Help/release/dev/cmake-parent-fix.rst b/Help/release/dev/cmake-parent-fix.rst
new file mode 100644
index 0000000..99fdcc7
--- /dev/null
+++ b/Help/release/dev/cmake-parent-fix.rst
@@ -0,0 +1,5 @@
+cmake-parent-fix
+----------------
+
+* :variable:`CMAKE_PARENT_LIST_FILE` is no longer defined when processing
+  a ``CMakeLists.txt`` file.  See policy :policy:`CMP0198`.
diff --git a/Help/release/dev/codemodel-version-directory-target-objects.rst b/Help/release/dev/codemodel-version-directory-target-objects.rst
new file mode 100644
index 0000000..8b31ef2
--- /dev/null
+++ b/Help/release/dev/codemodel-version-directory-target-objects.rst
@@ -0,0 +1,8 @@
+codemodel-version-directory-target-objects
+------------------------------------------
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 ``version`` field has
+  been updated to 2.9.
+
+* The :manual:`cmake-file-api(7)` "codemodel" version 2 "target" and
+  "directory" objects gained a new ``codemodelVersion`` field.
diff --git a/Help/release/dev/config-fix-matching.rst b/Help/release/dev/config-fix-matching.rst
new file mode 100644
index 0000000..0b929a0
--- /dev/null
+++ b/Help/release/dev/config-fix-matching.rst
@@ -0,0 +1,5 @@
+config-fix-matching
+-------------------
+
+The :genex:`$<CONFIG:cfgs>` generator expression no longer matches multiple
+configurations.  See policy :policy:`CMP0199`.
diff --git a/Help/release/dev/emscripten-platform.rst b/Help/release/dev/emscripten-platform.rst
new file mode 100644
index 0000000..4757227
--- /dev/null
+++ b/Help/release/dev/emscripten-platform.rst
@@ -0,0 +1,5 @@
+emscripten-platform
+-------------------
+
+* CMake now supports :ref:`Cross Compiling for Emscripten` with simple
+  toolchain files.
diff --git a/Help/release/dev/find-modules.rst b/Help/release/dev/find-modules.rst
new file mode 100644
index 0000000..c95384c
--- /dev/null
+++ b/Help/release/dev/find-modules.rst
@@ -0,0 +1,84 @@
+Find Modules
+------------
+
+* The :module:`FindALSA` module now provides a ``ALSA_VERSION`` result
+  variable.  The ``ALSA_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindArmadillo` module now provides an ``Armadillo_VERSION``,
+  and ``Armadillo_VERSION_NAME`` result variables.  The
+  ``ARMADILLO_VERSION_STRING``, ``ARMADILLO_VERSION_MAJOR``,
+  ``ARMADILLO_VERSION_MINOR``, ``ARMADILLO_VERSION_PATCH``, and
+  ``ARMADILLO_VERSION_NAME`` result variables are deprecated.
+
+* The :module:`FindBZip2` module now provides a ``BZip2_VERSION`` result
+  variable.  The ``BZIP2_VERSION`` result variable is deprecated.
+
+* The :module:`FindCups` module now provides a ``Cups_VERSION`` result
+  variable.  The ``CUPS_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindDoxygen` module now provides a ``Doxygen_VERSION`` result
+  variable.  The ``DOXYGEN_VERSION`` result variable is deprecated.
+
+* The :module:`FindEXPAT` module now provides a ``EXPAT_VERSION`` result
+  variable.  The ``EXPAT_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindFreetype` module now provides a ``Freetype_VERSION`` result
+  variable.  The ``FREETYPE_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindGettext` module now provides a ``Gettext_VERSION`` result
+  variable.  The ``GETTEXT_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindGnuplot` module now provides a ``Gnuplot_VERSION`` result
+  variable.  The ``GNUPLOT_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindGnuTLS` module now provides a ``GnuTLS_VERSION`` result
+  variable.  The ``GNUTLS_VERSION`` result variable is deprecated.
+
+* The :module:`FindJasper` module now provides a ``Jasper_VERSION`` result
+  variable.  The ``JASPER_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindLibLZMA` module now provides a ``LibLZMA_VERSION`` result
+  variable.  The ``LIBLZMA_VERSION`` result variable is deprecated.
+
+* The :module:`FindLibXml2` module now provides a ``LibXml2_VERSION`` result
+  variable.  The ``LIBXML2_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindLibXslt` module now provides a ``LibXslt_VERSION`` result
+  variable.  The ``LIBXSLT_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindLTTngUST` module now provides a ``LTTngUST_VERSION`` result
+  variable.  The ``LTTNGUST_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindOpenSceneGraph` module now provides an
+  ``OpenSceneGraph_VERSION`` result variable.  The ``OPENSCENEGRAPH_VERSION``
+  result variable is deprecated.
+
+* The :module:`FindOpenSSL` module now provides an ``OpenSSL_VERSION`` result
+  variable.  The ``OPENSSL_VERSION`` result variable is deprecated.
+
+* The :module:`FindPerl` module now provides a ``Perl_VERSION`` result
+  variable.  The ``PERL_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindPerlLibs` module now provides a ``PerlLibs_VERSION``
+  result variable.
+
+* The :module:`FindPNG` module now provides a ``PNG_VERSION`` result
+  variable.  The ``PNG_VERSION_STRING`` result variable is deprecated.
+
+* The :module:`FindPostgreSQL` module now provides a ``PostgreSQL_VERSION``
+  result variable.  The ``PostgreSQL_VERSION_STRING`` result variable is
+  deprecated.
+
+* The :module:`FindSDL_gfx`, :module:`FindSDL_image`, :module:`FindSDL_mixer`,
+  :module:`FindSDL_net`, :module:`FindSDL_sound`, and :module:`FindSDL_ttf`
+  modules now provide their respective ``<PackageName>_VERSION`` result
+  variables. Previous ``<PACKAGENAME>_VERSION_STRING`` result variables
+  are deprecated.
+
+* The :module:`FindSquish` module now provides a ``Squish_VERSION`` result
+  variable.  The ``SQUISH_VERSION``, ``SQUISH_VERSION_MAJOR``,
+  ``SQUISH_VERSION_MINOR``, and ``SQUISH_VERSION_PATCH`` result variables
+  are deprecated.
+
+* The :module:`FindTIFF` module now provides a ``TIFF_VERSION`` result
+  variable.  The ``TIFF_VERSION_STRING`` result variable is deprecated.
diff --git a/Help/release/dev/find-package-UNWIND_INCLUDE.rst b/Help/release/dev/find-package-UNWIND_INCLUDE.rst
new file mode 100644
index 0000000..8be5d97
--- /dev/null
+++ b/Help/release/dev/find-package-UNWIND_INCLUDE.rst
@@ -0,0 +1,6 @@
+find-package-UNWIND_INCLUDE
+---------------------------
+
+* The :command:`find_package()` command gained a new ``UNWIND_INCLUDE`` option
+  to enable immediate :command:`return` from :command:`include()` commands
+  after a failure to discover a transitive dependency.
diff --git a/Help/release/dev/gtest-use-json-output-for-discovery.rst b/Help/release/dev/gtest-use-json-output-for-discovery.rst
new file mode 100644
index 0000000..09f2d35
--- /dev/null
+++ b/Help/release/dev/gtest-use-json-output-for-discovery.rst
@@ -0,0 +1,12 @@
+gtest-use-json-output-for-discovery
+-----------------------------------
+
+* The :command:`gtest_discover_tests()` command from the :module:`GoogleTest`
+  module now sets the ``DEF_SOURCE_LINE`` test property for each discovered
+  test if gtest supports the ``--gtest_output=json`` option.  This test
+  property is used by some IDEs to locate the source for each test.
+* The :command:`gtest_discover_tests()` command from the :module:`GoogleTest`
+  module previously parsed certain type-parameterized test names incorrectly.
+  Their names ended up with raw characters from gtest's output and were
+  very obviously misparsed.  Those names are now parsed correctly, so projects
+  may see different test names to before for affected tests.
diff --git a/Help/release/dev/ninja-per-source-job-pool.rst b/Help/release/dev/ninja-per-source-job-pool.rst
new file mode 100644
index 0000000..ff1abd8
--- /dev/null
+++ b/Help/release/dev/ninja-per-source-job-pool.rst
@@ -0,0 +1,5 @@
+ninja-per-source-job-pool
+-------------------------
+
+* The :prop_sf:`JOB_POOL_COMPILE` source file property was added
+  to assign individual source compilations to :prop_gbl:`JOB_POOLS`.
diff --git a/Help/release/dev/set_unset-CACHE.rst b/Help/release/dev/set_unset-CACHE.rst
new file mode 100644
index 0000000..727c653
--- /dev/null
+++ b/Help/release/dev/set_unset-CACHE.rst
@@ -0,0 +1,5 @@
+set-unset-CACHE
+---------------
+
+* The :command:`set` and :command:`unset` commands gain the support of the
+  ``CACHE{<variable>}`` syntax to handle cache entries.
diff --git a/Help/release/dev/short-object-names.rst b/Help/release/dev/short-object-names.rst
new file mode 100644
index 0000000..d6c9139
--- /dev/null
+++ b/Help/release/dev/short-object-names.rst
@@ -0,0 +1,20 @@
+short-object-names
+------------------
+
+* There is now the :variable:`CMAKE_INTERMEDIATE_DIR_STRATEGY` variable (and
+  associated environment variable :envvar:`CMAKE_INTERMEDIATE_DIR_STRATEGY`)
+  that may be used to change the strategy used to name intermediate
+  directories used for object files (and other associated target metadata). It
+  is supported for the following generators:
+
+  - :ref:`Ninja Generators`
+  - :ref:`Makefile Generators`
+  - :ref:`Visual Studio Generators`
+
+  Note that the strategy implementation may differ between generators.
+
+* There is now the :variable:`CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY`
+  variable (and associated environment variable
+  :envvar:`CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY`)
+  that may be used to change the strategy used to name intermediate
+  directories used for :manual:`Qt Autogen <cmake-qt(7)>` files.
diff --git a/Help/release/dev/vs14-deprecate.rst b/Help/release/dev/vs14-deprecate.rst
new file mode 100644
index 0000000..f3aab73
--- /dev/null
+++ b/Help/release/dev/vs14-deprecate.rst
@@ -0,0 +1,5 @@
+vs14-deprecate
+--------------
+
+* The :generator:`Visual Studio 14 2015` generator is now deprecated
+  and will be removed in a future version of CMake.
diff --git a/Help/release/index.rst b/Help/release/index.rst
index 400e1f2..64b933a 100644
--- a/Help/release/index.rst
+++ b/Help/release/index.rst
@@ -7,6 +7,8 @@
   This file should include the adjacent "dev.txt" file
   in development versions but not in release versions.
 
+.. include:: dev.txt
+
 Releases
 ========
 
diff --git a/Help/variable/CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY.rst b/Help/variable/CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY.rst
new file mode 100644
index 0000000..125690d
--- /dev/null
+++ b/Help/variable/CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY.rst
@@ -0,0 +1,27 @@
+CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY
+---------------------------------------
+
+.. versionadded:: 4.2
+
+``CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY`` is a string cache variable
+specifying the strategy to use for autogen target intermediate directories and
+their contents. The supported values are:
+
+- ``FULL``: Intermediate directories are named based on a
+  ``<TARGET_NAME>_autogen.dir`` and ``<TARGET_NAME>_autogen`` pattern (with
+  some slight deviations and sanitizations applied in various places). Object
+  file names are based on the filename of the source file being compiled.
+- ``SHORT``: Intermediate directories are named from the hash of the target
+  name and the build directory location and an ``/autogen`` subdirectory.
+  This may help with projects that generate long paths in the build directory
+  to support building in directories other than those near a root path.
+
+When unset or the named strategy is not supported, the ``FULL`` strategy is
+used.
+
+.. note::
+  This only works as a cache variable, not a locally-scoped variable.
+
+.. note::
+  Not all generators support all strategies and paths may differ between
+  generators.
diff --git a/Help/variable/CMAKE_BINARY_DIR.rst b/Help/variable/CMAKE_BINARY_DIR.rst
index 96c6319..b046037 100644
--- a/Help/variable/CMAKE_BINARY_DIR.rst
+++ b/Help/variable/CMAKE_BINARY_DIR.rst
@@ -11,3 +11,5 @@
 ``CMAKE_BINARY_DIR``, :variable:`CMAKE_SOURCE_DIR`,
 :variable:`CMAKE_CURRENT_BINARY_DIR` and
 :variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
+
+Modifying ``CMAKE_BINARY_DIR`` has undefined behavior.
diff --git a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
index 1d7a111..1eabaef 100644
--- a/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
+++ b/Help/variable/CMAKE_CURRENT_BINARY_DIR.rst
@@ -13,3 +13,5 @@
 :variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
 ``CMAKE_CURRENT_BINARY_DIR`` and
 :variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
+
+Modifying ``CMAKE_CURRENT_BINARY_DIR`` has undefined behavior.
diff --git a/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst b/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
index 4205efb..7a08892 100644
--- a/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_CURRENT_SOURCE_DIR.rst
@@ -10,3 +10,5 @@
 :variable:`CMAKE_BINARY_DIR`, :variable:`CMAKE_SOURCE_DIR`,
 :variable:`CMAKE_CURRENT_BINARY_DIR` and
 ``CMAKE_CURRENT_SOURCE_DIR`` to the current working directory.
+
+Modifying ``CMAKE_CURRENT_SOURCE_DIR`` has undefined behavior.
diff --git a/Help/variable/CMAKE_DL_LIBS.rst b/Help/variable/CMAKE_DL_LIBS.rst
index 50d313d..11fc742 100644
--- a/Help/variable/CMAKE_DL_LIBS.rst
+++ b/Help/variable/CMAKE_DL_LIBS.rst
@@ -1,7 +1,49 @@
 CMAKE_DL_LIBS
 -------------
 
-Name of library containing ``dlopen`` and ``dlclose``.
+This variable contains a name of the dynamic loading library, or a list of
+system libraries needed to use the ``dlopen()`` and ``dlclose()`` functions.
 
-The name of the library that has ``dlopen`` and ``dlclose`` in it, usually
-``-ldl`` on most UNIX machines.
+Few examples of the values this variable is set to:
+
+``dl``
+  On most Unix-like systems.
+
+``-lld``
+  On AIX, prior to CMake 4.2.
+
+``dld``
+  On HP-UX.
+
+""
+  Empty string value or not set on systems that have ``dl*()`` functions
+  either in the default library that is implicitly linked (e.g., BSD-like
+  systems, Haiku, macOS, SunOS, etc.), or on systems that don't provide these
+  functions (e.g., Windows).
+
+Examples
+^^^^^^^^
+
+Example: Linking Dynamic Loading Library
+""""""""""""""""""""""""""""""""""""""""
+
+Using this variable in a project that uses dynamic loading functionality:
+
+.. code-block:: cmake
+
+  target_link_libraries(example PRIVATE ${CMAKE_DL_LIBS})
+
+Example: Checking Symbols
+"""""""""""""""""""""""""
+
+Checking for symbols with the dynamic loading library linked during the check:
+
+.. code-block:: cmake
+
+  include(CheckSymbolExists)
+  include(CMakePushCheckState)
+
+  cmake_push_check_state(RESET)
+    set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS})
+    check_symbol_exists(dlopen "dlfcn.h" HAVE_DLOPEN)
+  cmake_pop_check_state()
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
index 92758fd..033748a 100644
--- a/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
+++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst
@@ -3,16 +3,21 @@
 
 .. versionadded:: 3.7
 
+.. versionchanged:: 4.2
+
+  The default sort direction has changed from ``DEC`` to ``ASC``.
+
+
 The sorting direction used by :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`.
 It can assume one of the following values:
 
 ``ASC``
-  Default.  Ordering is done in ascending mode.
+  Ordering is done in ascending mode.
   The lowest folder found will be tested first.
 
 ``DEC``
-  Ordering is done in descending mode.
+  Default. Ordering is done in descending mode.
   The highest folder found will be tested first.
 
-If :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` is not set or is set to ``NONE``
-this variable has no effect.
+If :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` is set to ``NONE`` this variable
+has no effect.
diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
index f1016d9..524b2ef 100644
--- a/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
+++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst
@@ -3,39 +3,40 @@
 
 .. versionadded:: 3.7
 
+.. versionchanged:: 4.2
+
+  The default sort order has changed from ``NONE`` to ``NATURAL``.
+
+
 The default order for sorting directories which match a search path containing
 a glob expression found using :command:`find_package`.  It can assume one of
 the following values:
 
 ``NONE``
-  Default.  No attempt is done to sort directories.
+  No attempt is done to sort directories.
   The first valid package found will be selected.
 
 ``NAME``
   Sort directories lexicographically before searching.
 
 ``NATURAL``
-  Sort directories using natural order (see ``strverscmp(3)`` manual),
+  Default. Sort directories using natural order (see ``strverscmp(3)`` manual),
   i.e. such that contiguous digits are compared as whole numbers.
 
-Natural sorting can be employed to return the highest version when multiple
-versions of the same library are available to be found by
-:command:`find_package`.  For example suppose that the following libraries
-have package configuration files on disk, in a directory of the same name,
-with all such directories residing in the same parent directory:
+Natural sorting is employed by default to return the highest version when
+multiple versions of the same library are available to be found by
+:command:`find_package`.  For example suppose that the following libraries have
+package configuration files on disk, in a directory of the same name, with all
+such directories residing in the same parent directory:
 
-* libX-1.1.0
-* libX-1.2.9
-* libX-1.2.10
+* ``libX-1.1.0``
+* ``libX-1.2.9``
+* ``libX-1.2.10``
 
-By setting ``NATURAL`` order we can select the one with the highest
-version number ``libX-1.2.10``.
-
-.. code-block:: cmake
-
-  set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
-  find_package(libX CONFIG)
+The default order of ``NATURAL`` will select the one with the highest version
+number, i.e. ``libX-1.2.10``.
 
 The sort direction can be controlled using the
-:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable
-(by default descending, e.g. lib-B will be tested before lib-A).
+:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable (by default descending,
+i.e. ``libX-1.2`` will be tested before ``libX-1.0`` and  ``lib-B`` will be
+tested before ``lib-A``).
diff --git a/Help/variable/CMAKE_INTERMEDIATE_DIR_STRATEGY.rst b/Help/variable/CMAKE_INTERMEDIATE_DIR_STRATEGY.rst
new file mode 100644
index 0000000..4b0849a
--- /dev/null
+++ b/Help/variable/CMAKE_INTERMEDIATE_DIR_STRATEGY.rst
@@ -0,0 +1,28 @@
+CMAKE_INTERMEDIATE_DIR_STRATEGY
+-------------------------------
+
+.. versionadded:: 4.2
+
+``CMAKE_INTERMEDIATE_DIR_STRATEGY`` is a string cache variable specifying the
+strategy to use for target intermediate directories and their contents. The
+supported values are:
+
+- ``FULL``: Intermediate directories are named based on a
+  ``<TARGET_NAME>.dir`` pattern (with some slight deviations and sanitizations
+  applied in various places). Object file names are based on the filename of
+  the source file being compiled.
+- ``SHORT``: Intermediate directories are named from the hash of the target
+  name and the build directory location. Object file names are based on hashes
+  of the source file name to reduce path lengths. This may help with projects
+  that generate long paths in the build directory to support building in
+  directories other than those near a root path.
+
+When unset or the named strategy is not supported, the ``FULL`` strategy is
+used.
+
+.. note::
+  This only works as a cache variable, not a locally-scoped variable.
+
+.. note::
+  Not all generators support all strategies and paths may differ between
+  generators.
diff --git a/Help/variable/CMAKE_LANG_BYTE_ORDER.rst b/Help/variable/CMAKE_LANG_BYTE_ORDER.rst
index 78f0ae6..da60af6 100644
--- a/Help/variable/CMAKE_LANG_BYTE_ORDER.rst
+++ b/Help/variable/CMAKE_LANG_BYTE_ORDER.rst
@@ -18,3 +18,78 @@
 If :variable:`CMAKE_OSX_ARCHITECTURES` specifies multiple architectures, the
 value of ``CMAKE_<LANG>_BYTE_ORDER`` is non-empty only if all architectures
 share the same byte order.
+
+Examples
+^^^^^^^^
+
+Example: Checking Endianness
+""""""""""""""""""""""""""""
+
+Checking endianness (byte order) of the target architecture in a CMake
+project, where ``C`` language is one of the enabled languages, and storing
+the result in a variable ``WORDS_BIGENDIAN``:
+
+.. code-block:: cmake
+
+  if(CMAKE_C_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+    set(WORDS_BIGENDIAN TRUE)
+  elseif(CMAKE_C_BYTE_ORDER STREQUAL "LITTLE_ENDIAN")
+    set(WORDS_BIGENDIAN FALSE)
+  else()
+    set(WORDS_BIGENDIAN FALSE)
+    message(WARNING "Endianness could not be determined.")
+  endif()
+
+Or, if the project doesn't have ``C`` language enabled, it can be replaced
+with some other enabled language.  For example, if ``CXX`` is enabled:
+
+.. code-block:: cmake
+
+  if(CMAKE_CXX_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+    set(WORDS_BIGENDIAN TRUE)
+  elseif(CMAKE_CXX_BYTE_ORDER STREQUAL "LITTLE_ENDIAN")
+    set(WORDS_BIGENDIAN FALSE)
+  else()
+    set(WORDS_BIGENDIAN FALSE)
+    message(WARNING "Endianness could not be determined.")
+  endif()
+
+Note, that in most cases this can be simplified by only checking for a
+big-endian target:
+
+.. code-block:: cmake
+
+  if(CMAKE_C_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+    set(WORDS_BIGENDIAN TRUE)
+  else()
+    set(WORDS_BIGENDIAN FALSE)
+  endif()
+
+Example: Per-language Endianness Check
+""""""""""""""""""""""""""""""""""""""
+
+Most of the time, architectures used today are consistent in endianness
+across compilers.  But here's when per-language endianness check can matter:
+
+* Cross-compilation to different architectures (e.g., big-endian embedded
+  system).
+
+* Heterogeneous toolchains where one target architecture is for C language
+  and another target is for different language.
+
+* Static libraries or binaries reused across platforms (e.g., distributing
+  precompiled CUDA kernels).
+
+.. code-block:: cmake
+
+  if(CMAKE_C_BYTE_ORDER)
+    message(STATUS "C byte order: ${CMAKE_C_BYTE_ORDER}")
+  endif()
+
+  if(CMAKE_CXX_BYTE_ORDER)
+    message(STATUS "C++ byte order: ${CMAKE_CXX_BYTE_ORDER}")
+  endif()
+
+  if(CMAKE_CUDA_BYTE_ORDER)
+    message(STATUS "CUDA byte order: ${CMAKE_CUDA_BYTE_ORDER}")
+  endif()
diff --git a/Help/variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID.rst b/Help/variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID.rst
index 1efbf1c..ff54da2 100644
--- a/Help/variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID.rst
+++ b/Help/variable/CMAKE_LANG_COMPILER_ARCHITECTURE_ID.rst
@@ -123,6 +123,9 @@
 ``sparcv9``
   SPARC 64-bit
 
+``sw_64``
+  Sunway
+
 ``x86_64``
   Intel 64-bit
 
diff --git a/Help/variable/CMAKE_LANG_LINK_MODE.rst b/Help/variable/CMAKE_LANG_LINK_MODE.rst
index 6025671..f8286e4 100644
--- a/Help/variable/CMAKE_LANG_LINK_MODE.rst
+++ b/Help/variable/CMAKE_LANG_LINK_MODE.rst
@@ -12,3 +12,8 @@
   The linker is used directly for the link step.
 
 This variable is read-only. Setting it is undefined behavior.
+
+See Also
+^^^^^^^^
+
+* The :variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>` variable.
diff --git a/Help/variable/CMAKE_LANG_USING_LINKER_MODE.rst b/Help/variable/CMAKE_LANG_USING_LINKER_MODE.rst
index 7b252aa..a3d6c97 100644
--- a/Help/variable/CMAKE_LANG_USING_LINKER_MODE.rst
+++ b/Help/variable/CMAKE_LANG_USING_LINKER_MODE.rst
@@ -1,10 +1,17 @@
 CMAKE_<LANG>_USING_LINKER_MODE
 ------------------------------
 
+.. deprecated:: 4.0
+
+  This variable is no longer used.  The type of information stored in the
+  :variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>` variable is determined by
+  the :variable:`CMAKE_<LANG>_LINK_MODE` variable.
+
 .. versionadded:: 3.29
 
-This controls how the value of the :variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>`
-variable should be interpreted. The supported linker mode values are:
+This variable controls how the value of the
+:variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>` variable should be interpreted.
+The supported linker mode values are:
 
 ``FLAG``
   :variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>` holds a
@@ -22,11 +29,5 @@
 
   * value ``TOOL`` is expected and required when the linker is used directly
     for the link step.
-  * value ``FLAGS`` is expected or the variable not set when the compiler is
+  * value ``FLAG`` is expected or the variable not set when the compiler is
     used as driver for the link step.
-
-.. deprecated:: 4.0
-
-This variable is no longer used. The type of information stored in the
-:variable:`CMAKE_<LANG>_USING_LINKER_<TYPE>` variable is determined by the
-:variable:`CMAKE_<LANG>_LINK_MODE` variable.
diff --git a/Help/variable/CMAKE_PARENT_LIST_FILE.rst b/Help/variable/CMAKE_PARENT_LIST_FILE.rst
index 7e71efa..c0c6469 100644
--- a/Help/variable/CMAKE_PARENT_LIST_FILE.rst
+++ b/Help/variable/CMAKE_PARENT_LIST_FILE.rst
@@ -8,7 +8,8 @@
 including it.
 
 While processing a ``CMakeLists.txt`` file, even in subdirectories,
-this variable has the same value as :variable:`CMAKE_CURRENT_LIST_FILE`.
+this variable is not defined.  See policy :policy:`CMP0198`.
+
 While processing a :option:`cmake -P` script, this variable is not defined
 in the outermost script.
 
diff --git a/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst b/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
index f83246a..19f5e57 100644
--- a/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
+++ b/Help/variable/CMAKE_POSITION_INDEPENDENT_CODE.rst
@@ -1,9 +1,19 @@
 CMAKE_POSITION_INDEPENDENT_CODE
 -------------------------------
 
-Default value for :prop_tgt:`POSITION_INDEPENDENT_CODE` of targets.
+Default value for the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property.
 
 This variable is used to initialize the
 :prop_tgt:`POSITION_INDEPENDENT_CODE` property on targets that
 are not ``SHARED`` or ``MODULE`` library targets.
 If set, its value is also used by the :command:`try_compile` command.
+
+The ``SHARED`` and ``MODULE`` library targets have by default position
+independent code enabled regardless of this variable.  To disable PIC on
+these library types, only manually setting the target property disables it.
+
+See Also
+^^^^^^^^
+
+* The :module:`CheckPIESupported` module to pass PIE-related options to the
+  linker for executables.
diff --git a/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst b/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst
new file mode 100644
index 0000000..0cbde7c
--- /dev/null
+++ b/Help/variable/CMAKE_PROJECT_SPDX_LICENSE.rst
@@ -0,0 +1,41 @@
+CMAKE_PROJECT_SPDX_LICENSE
+--------------------------
+
+.. versionadded:: 4.2
+
+.. note::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+The license(s) of the top level project.
+
+This variable holds the license expression of the project as specified in the
+top level CMakeLists.txt file by a :command:`project` command.  In the event
+that the top level CMakeLists.txt contains multiple :command:`project` calls,
+the most recently called one from that top level CMakeLists.txt will determine
+the value that ``CMAKE_PROJECT_SPDX_LICENSE`` contains.  For example, consider
+the following top level CMakeLists.txt:
+
+.. code-block:: cmake
+
+  cmake_minimum_required(VERSION 4.2)
+  project(First SPDX_LICENSE "BSD-3-Clause")
+  project(Second SPDX_LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
+  add_subdirectory(sub)
+  project(Third SPDX_LICENSE "BSD-3-Clause AND CC0-1.0")
+
+And ``sub/CMakeLists.txt`` with the following contents:
+
+.. code-block:: cmake
+
+  project(SubProj SPDX_LICENSE Apache-2.0)
+  message("CMAKE_PROJECT_SPDX_LICENSE = ${CMAKE_PROJECT_SPDX_LICENSE}")
+
+The most recently seen :command:`project` command from the top level
+CMakeLists.txt would be ``project(Second ...)``, so this will print::
+
+  CMAKE_PROJECT_SPDX_LICENSE = BSD-3-Clause AND CC-BY-SA-4.0
+
+To obtain the version from the most recent call to :command:`project` in
+the current directory scope or above, see the :variable:`PROJECT_SPDX_LICENSE`
+variable.
diff --git a/Help/variable/CMAKE_SOURCE_DIR.rst b/Help/variable/CMAKE_SOURCE_DIR.rst
index f1d1bee..be28f4d 100644
--- a/Help/variable/CMAKE_SOURCE_DIR.rst
+++ b/Help/variable/CMAKE_SOURCE_DIR.rst
@@ -11,3 +11,5 @@
 :variable:`CMAKE_BINARY_DIR`, ``CMAKE_SOURCE_DIR``,
 :variable:`CMAKE_CURRENT_BINARY_DIR` and
 :variable:`CMAKE_CURRENT_SOURCE_DIR` to the current working directory.
+
+Modifying ``CMAKE_SOURCE_DIR`` has undefined behavior.
diff --git a/Help/variable/CMAKE_SYSTEM_NAME.rst b/Help/variable/CMAKE_SYSTEM_NAME.rst
index 41c1b78..de688b5 100644
--- a/Help/variable/CMAKE_SYSTEM_NAME.rst
+++ b/Help/variable/CMAKE_SYSTEM_NAME.rst
@@ -104,3 +104,15 @@
 * Cygwin's ``cmake`` package (``/usr/bin/cmake``) uses system name ``CYGWIN``.
   A non-cygwin CMake on Windows (e.g. ``$PROGRAMFILES/CMake/bin/cmake``)
   uses system name ``Windows`` even when it runs under a Cygwin environment.
+
+Removed Platforms
+^^^^^^^^^^^^^^^^^
+
+The following platforms were once supported by CMake and got removed either due
+to platform's EOL, or other incompatibilities:
+
+========================= ===================================== ================
+Value                     Name                                  Removed in CMake
+========================= ===================================== ================
+``kFreeBSD``              FreeBSD kernel with a GNU userland    4.1
+========================= ===================================== ================
diff --git a/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst b/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst
new file mode 100644
index 0000000..06c395d
--- /dev/null
+++ b/Help/variable/PROJECT-NAME_SPDX_LICENSE.rst
@@ -0,0 +1,11 @@
+<PROJECT-NAME>_SPDX_LICENSE
+---------------------------
+
+.. versionadded:: 4.2
+
+.. note::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+Value given to the ``SPDX_LICENSE`` option of the most recent call to the
+:command:`project` command with project name ``<PROJECT-NAME>``, if any.
diff --git a/Help/variable/PROJECT_SPDX_LICENSE.rst b/Help/variable/PROJECT_SPDX_LICENSE.rst
new file mode 100644
index 0000000..4f62e94
--- /dev/null
+++ b/Help/variable/PROJECT_SPDX_LICENSE.rst
@@ -0,0 +1,12 @@
+PROJECT_SPDX_LICENSE
+--------------------
+
+.. versionadded:: 4.2
+
+.. note::
+
+  Experimental. Gated by ``CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO``.
+
+Value given to the ``SPDX_LICENSE`` option of the most recent call to the
+:command:`project` command, if any. To obtain the compatibility version of the
+top level project, see the :variable:`CMAKE_PROJECT_SPDX_LICENSE` variable.
diff --git a/Modules/AddFileDependencies.cmake b/Modules/AddFileDependencies.cmake
index 13828f2..25a78a8 100644
--- a/Modules/AddFileDependencies.cmake
+++ b/Modules/AddFileDependencies.cmake
@@ -6,28 +6,38 @@
 -------------------
 
 .. deprecated:: 3.20
+  Do not use this module in new code.
 
-Add dependencies to a source file.
+  Instead use the :command:`set_property` command to append to the
+  :prop_sf:`OBJECT_DEPENDS` source file property directly:
+
+  .. code-block:: cmake
+
+    set_property(SOURCE <source> APPEND PROPERTY OBJECT_DEPENDS <files>...)
+
+Load this module in a CMake project with:
 
 .. code-block:: cmake
 
-  add_file_dependencies(<source> <files>...)
+  include(AddFileDependencies)
 
-Adds the given ``<files>`` to the dependencies of file ``<source>``.
+Commands
+^^^^^^^^
 
-Do not use this command in new code.  It is just a wrapper around:
+This module provides the following command:
 
-.. code-block:: cmake
+.. command:: add_file_dependencies
 
-  set_property(SOURCE <source> APPEND PROPERTY OBJECT_DEPENDS <files>...)
+  Adds dependencies to a source file:
 
-Instead use the :command:`set_property` command to append to the
-:prop_sf:`OBJECT_DEPENDS` source file property directly.
+  .. code-block:: cmake
 
+    add_file_dependencies(<source> <files>...)
+
+  This command adds the given ``<files>`` to the dependencies of file
+  ``<source>``.
 #]=======================================================================]
 
 function(add_file_dependencies _file)
-
   set_property(SOURCE "${_file}" APPEND PROPERTY OBJECT_DEPENDS "${ARGN}")
-
 endfunction()
diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake
index 4df5bb9..0c7fede 100644
--- a/Modules/BundleUtilities.cmake
+++ b/Modules/BundleUtilities.cmake
@@ -733,7 +733,9 @@
     string(REGEX REPLACE "rpath " "" load_cmds_ov "${load_cmds_ov}")
     if(load_cmds_ov)
       foreach(rpath ${load_cmds_ov})
-        gp_append_unique(${rpaths_var} "${rpath}")
+        if(NOT rpath IN_LIST ${rpaths_var})
+          list(APPEND ${rpaths_var} "${rpath}")
+        endif()
       endforeach()
     endif()
   endif()
@@ -744,7 +746,9 @@
     foreach(rpath ${rpath_var} ${runpath_var})
       # Substitute $ORIGIN with the exepath and add to the found rpaths
       string(REPLACE "$ORIGIN" "${item_dir}" rpath "${rpath}")
-      gp_append_unique(${rpaths_var} "${rpath}")
+      if(NOT rpath IN_LIST ${rpaths_var})
+        list(APPEND ${rpaths_var} "${rpath}")
+      endif()
     endforeach()
   endif()
 
@@ -787,7 +791,9 @@
   get_item_key("${item}" key)
 
   list(LENGTH ${keys_var} length_before)
-  gp_append_unique(${keys_var} "${key}")
+  if(NOT key IN_LIST ${keys_var})
+    list(APPEND ${keys_var} "${key}")
+  endif()
   list(LENGTH ${keys_var} length_after)
 
   if(NOT length_before EQUAL length_after)
diff --git a/Modules/CMakeCompilerABI.h b/Modules/CMakeCompilerABI.h
index dc71f9f..40c5be4 100644
--- a/Modules/CMakeCompilerABI.h
+++ b/Modules/CMakeCompilerABI.h
@@ -114,6 +114,8 @@
 #  define ARCHITECTURE_ID "riscv64"
 #elif defined(__riscv) && __riscv_xlen == 32
 #  define ARCHITECTURE_ID "riscv32"
+#elif defined(__sw_64)
+#  define ARCHITECTURE_ID "sw_64"
 #elif defined(__s390x__)
 #  define ARCHITECTURE_ID "s390x"
 #elif defined(__s390__)
diff --git a/Modules/CMakeFindBinUtils.cmake b/Modules/CMakeFindBinUtils.cmake
index 1948c63..91543a6 100644
--- a/Modules/CMakeFindBinUtils.cmake
+++ b/Modules/CMakeFindBinUtils.cmake
@@ -219,6 +219,11 @@
     list(PREPEND _CMAKE_LINKER_NAMES "armlink")
   endif()
 
+  if(EMSCRIPTEN)
+    list(PREPEND _CMAKE_AR_NAMES "emar")
+    list(PREPEND _CMAKE_RANLIB_NAMES "emranlib")
+  endif()
+
   list(APPEND _CMAKE_TOOL_VARS AR RANLIB STRIP LINKER NM OBJDUMP OBJCOPY READELF DLLTOOL ADDR2LINE TAPI)
 endif()
 
@@ -259,8 +264,7 @@
 
 
 if(CMAKE_PLATFORM_HAS_INSTALLNAME)
-  find_program(CMAKE_INSTALL_NAME_TOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}install_name_tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
-
+  find_program(CMAKE_INSTALL_NAME_TOOL NAMES ${_CMAKE_TOOLCHAIN_PREFIX}install_name_tool llvm-install-name-tool HINTS ${_CMAKE_TOOLCHAIN_LOCATION} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH)
   if(NOT CMAKE_INSTALL_NAME_TOOL)
     message(FATAL_ERROR "Could not find install_name_tool, please check your installation.")
   endif()
diff --git a/Modules/CMakeFindDependencyMacro.cmake b/Modules/CMakeFindDependencyMacro.cmake
index 99624d2..cf2c250 100644
--- a/Modules/CMakeFindDependencyMacro.cmake
+++ b/Modules/CMakeFindDependencyMacro.cmake
@@ -56,44 +56,59 @@
 
 #]=======================================================================]
 
-macro(find_dependency dep)
+macro(__find_dependency_common cmake_fd_call_hash dep)
+  set(cmake_fd_quiet_arg)
+  if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
+    set(cmake_fd_quiet_arg QUIET)
+  endif()
+  set(cmake_fd_required_arg)
+  if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
+    set(cmake_fd_required_arg REQUIRED)
+  endif()
+
+  get_property(cmake_fd_alreadyTransitive GLOBAL PROPERTY
+    _CMAKE_${dep}_TRANSITIVE_DEPENDENCY
+    )
+
+  find_package(${dep} ${ARGN}
+    ${cmake_fd_quiet_arg}
+    ${cmake_fd_required_arg}
+    )
+  set("_CMAKE_${dep}_${cmake_fd_call_hash}_FOUND" "${${dep}_FOUND}")
+
+  if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
+    set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
+  endif()
+
+  unset(cmake_fd_alreadyTransitive)
+  unset(cmake_fd_quiet_arg)
+  unset(cmake_fd_required_arg)
+endmacro()
+
+macro(__find_dependency_no_return dep)
   string(SHA256 cmake_fd_call_hash "${dep};${ARGN};${${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED}")
   if(_CMAKE_${dep}_${cmake_fd_call_hash}_FOUND)
-    unset(cmake_fd_call_hash)
+    set(${dep}_FOUND ${_CMAKE_${dep}_${cmake_fd_call_hash}_FOUND})
   else()
-    list(APPEND _CMAKE_${dep}_HASH_STACK ${cmake_fd_call_hash})
-    set(cmake_fd_quiet_arg)
-    if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
-      set(cmake_fd_quiet_arg QUIET)
-    endif()
-    set(cmake_fd_required_arg)
-    if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
-      set(cmake_fd_required_arg REQUIRED)
-    endif()
-
-    get_property(cmake_fd_alreadyTransitive GLOBAL PROPERTY
-      _CMAKE_${dep}_TRANSITIVE_DEPENDENCY
-      )
-
-    find_package(${dep} ${ARGN}
-      ${cmake_fd_quiet_arg}
-      ${cmake_fd_required_arg}
-      )
-    list(POP_BACK _CMAKE_${dep}_HASH_STACK cmake_fd_call_hash)
-    set("_CMAKE_${dep}_${cmake_fd_call_hash}_FOUND" "${${dep}_FOUND}")
-
-    if(NOT DEFINED cmake_fd_alreadyTransitive OR cmake_fd_alreadyTransitive)
-      set_property(GLOBAL PROPERTY _CMAKE_${dep}_TRANSITIVE_DEPENDENCY TRUE)
-    endif()
-
-    unset(cmake_fd_alreadyTransitive)
-    unset(cmake_fd_call_hash)
-    unset(cmake_fd_quiet_arg)
-    unset(cmake_fd_required_arg)
+    __find_dependency_common(${cmake_fd_call_hash} ${ARGV})
     if (NOT ${dep}_FOUND)
       set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency ${dep} could not be found.")
       set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
+    endif()
+  endif()
+  unset(cmake_fd_call_hash)
+endmacro()
+
+macro(find_dependency dep)
+  string(SHA256 cmake_fd_call_hash "${dep};${ARGN};${${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED}")
+  if(NOT _CMAKE_${dep}_${cmake_fd_call_hash}_FOUND)
+    __find_dependency_common(${cmake_fd_call_hash} ${ARGV})
+    if (NOT ${dep}_FOUND)
+      set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency ${dep} could not be found.")
+      set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
+      unset(cmake_fd_call_hash)
       return()
     endif()
   endif()
+  unset(cmake_fd_call_hash)
 endmacro()
diff --git a/Modules/CMakeForceCompiler.cmake b/Modules/CMakeForceCompiler.cmake
index e85c3f9..9b85c68 100644
--- a/Modules/CMakeForceCompiler.cmake
+++ b/Modules/CMakeForceCompiler.cmake
@@ -9,66 +9,98 @@
 
   Do not use.
 
-The macros provided by this module were once intended for use by
-cross-compiling toolchain files when CMake was not able to automatically
-detect the compiler identification.  Since the introduction of this module,
-CMake's compiler identification capabilities have improved and can now be
-taught to recognize any compiler.  Furthermore, the suite of information
-CMake detects from a compiler is now too extensive to be provided by
-toolchain files using these macros.
+  The commands provided by this module were once intended for use by
+  cross-compiling toolchain files when CMake was not able to automatically
+  detect the compiler identification.  Since the introduction of this module,
+  CMake's compiler identification capabilities have improved and can now be
+  taught to recognize any compiler.  Furthermore, the suite of information
+  CMake detects from a compiler is now too extensive to be provided by
+  toolchain files using these macros.
 
-One common use case for this module was to skip CMake's checks for a
-working compiler when using a cross-compiler that cannot link binaries
-without special flags or custom linker scripts.  This case is now supported
-by setting the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable in the
-toolchain file instead.
+  One common use case for this module was to skip CMake's checks for a
+  working compiler when using a cross-compiler that cannot link binaries
+  without special flags or custom linker scripts.  This case is now supported
+  by setting the :variable:`CMAKE_TRY_COMPILE_TARGET_TYPE` variable in the
+  toolchain file instead.
 
--------------------------------------------------------------------------
-
-Macro ``CMAKE_FORCE_C_COMPILER`` has the following signature:
+Load this module in a CMake toolchain file:
 
 .. code-block:: cmake
 
-   CMAKE_FORCE_C_COMPILER(<compiler> <compiler-id>)
+  include(CMakeForceCompiler)
 
-It sets :variable:`CMAKE_C_COMPILER <CMAKE_<LANG>_COMPILER>` to
-the given compiler and the cmake internal variable
-:variable:`CMAKE_C_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
-compiler-id.  It also bypasses the check for working compiler and basic
-compiler information tests.
+Commands
+^^^^^^^^
 
-Macro ``CMAKE_FORCE_CXX_COMPILER`` has the following signature:
+This module provides the following commands:
+
+.. command:: cmake_force_c_compiler
+
+  Sets the :variable:`CMAKE_C_COMPILER <CMAKE_<LANG>_COMPILER>` variable to
+  the given compiler and the :variable:`CMAKE_C_COMPILER_ID
+  <CMAKE_<LANG>_COMPILER_ID>` variable to the given compiler-id:
+
+  .. code-block:: cmake
+
+    cmake_force_c_compiler(<compiler> <compiler-id>)
+
+  This command also bypasses the check for working compiler and basic
+  compiler information tests.
+
+.. command:: cmake_force_cxx_compiler
+
+  Sets the :variable:`CMAKE_CXX_COMPILER <CMAKE_<LANG>_COMPILER>` variable
+  to the given compiler and the :variable:`CMAKE_CXX_COMPILER_ID
+  <CMAKE_<LANG>_COMPILER_ID>` variable to the given compiler-id:
+
+  .. code-block:: cmake
+
+    cmake_force_cxx_compiler(<compiler> <compiler-id>)
+
+  This command also bypasses the check for working compiler and basic
+  compiler information tests.
+
+.. command:: cmake_force_fortran_compiler
+
+  Sets the :variable:`CMAKE_Fortran_COMPILER <CMAKE_<LANG>_COMPILER>`
+  variable to the given compiler and the
+  :variable:`CMAKE_Fortran_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` variable
+  to the given compiler-id:
+
+  .. code-block:: cmake
+
+    cmake_force_fortran_compiler(<compiler> <compiler-id>)
+
+  This command also bypasses the check for working compiler and basic
+  compiler information tests.
+
+Examples
+^^^^^^^^
+
+A simple toolchain file using this module could look like this:
 
 .. code-block:: cmake
+  :caption: ``cmake/toolchains/example-toolchain.cmake``
 
-   CMAKE_FORCE_CXX_COMPILER(<compiler> <compiler-id>)
+  include(CMakeForceCompiler)
+  set(CMAKE_SYSTEM_NAME Generic)
+  cmake_force_c_compiler(chc12 MetrowerksHicross)
+  cmake_force_cxx_compiler(chc12 MetrowerksHicross)
 
-It sets :variable:`CMAKE_CXX_COMPILER <CMAKE_<LANG>_COMPILER>` to
-the given compiler and the cmake internal variable
-:variable:`CMAKE_CXX_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
-compiler-id.  It also bypasses the check for working compiler and basic
-compiler information tests.
-
-Macro ``CMAKE_FORCE_Fortran_COMPILER`` has the following signature:
+In new CMake code, compiler is detected automatically when setting required
+variables instead:
 
 .. code-block:: cmake
+  :caption: ``cmake/toolchains/example-toolchain.cmake``
 
-   CMAKE_FORCE_Fortran_COMPILER(<compiler> <compiler-id>)
+  set(CMAKE_SYSTEM_NAME Generic)
+  set(CMAKE_C_COMPILER chc12)
+  set(CMAKE_CXX_COMPILER chc12)
 
-It sets :variable:`CMAKE_Fortran_COMPILER <CMAKE_<LANG>_COMPILER>` to
-the given compiler and the cmake internal variable
-:variable:`CMAKE_Fortran_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` to the given
-compiler-id.  It also bypasses the check for working compiler and basic
-compiler information tests.
+See Also
+^^^^^^^^
 
-So a simple toolchain file could look like this:
-
-.. code-block:: cmake
-
-   include (CMakeForceCompiler)
-   set(CMAKE_SYSTEM_NAME Generic)
-   CMAKE_FORCE_C_COMPILER   (chc12 MetrowerksHicross)
-   CMAKE_FORCE_CXX_COMPILER (chc12 MetrowerksHicross)
+* :manual:`cmake-toolchains(7)`
 #]=======================================================================]
 
 macro(CMAKE_FORCE_C_COMPILER compiler id)
diff --git a/Modules/CMakeFortranCompilerABI.F b/Modules/CMakeFortranCompilerABI.F
index 81676cb..e9e0552 100644
--- a/Modules/CMakeFortranCompilerABI.F
+++ b/Modules/CMakeFortranCompilerABI.F
@@ -113,6 +113,8 @@
         PRINT *, 'INFO:arch[riscv64]'
 #elif defined(__riscv) && __riscv_xlen == 32
         PRINT *, 'INFO:arch[riscv32]'
+#elif defined(__sw_64) || defined(__sw_64__)
+        PRINT *, 'INFO:arch[sw_64]'
 #elif defined(__s390x__)
         PRINT *, 'INFO:arch[s390x]'
 #elif defined(__s390__)
diff --git a/Modules/CMakeFortranCompilerABI.F90 b/Modules/CMakeFortranCompilerABI.F90
index 2a9259b..0246d2a 100644
--- a/Modules/CMakeFortranCompilerABI.F90
+++ b/Modules/CMakeFortranCompilerABI.F90
@@ -105,6 +105,8 @@
 PRINT *, 'INFO:arch[loongarch32]'
 #elif defined(__m68k__)
 PRINT *, 'INFO:arch[m68k]'
+#elif defined(__sw_64)
+PRINT *, 'INFO:arch[sw_64]'
 #elif defined(__mips64) || defined(__mips64__)
 #  if defined(_MIPSEL)
 PRINT *, 'INFO:arch[mips64el]'
diff --git a/Modules/CMakeGraphVizOptions.cmake b/Modules/CMakeGraphVizOptions.cmake
index 1d7dc0f..ee1c55a 100644
--- a/Modules/CMakeGraphVizOptions.cmake
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -5,146 +5,9 @@
 CMakeGraphVizOptions
 --------------------
 
-The builtin Graphviz support of CMake.
+.. note::
 
-Generating Graphviz files
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-CMake can generate `Graphviz <https://www.graphviz.org/>`_ files showing the
-dependencies between the targets in a project, as well as external libraries
-which are linked against.
-
-When running CMake with the ``--graphviz=foo.dot`` option, it produces:
-
-* a ``foo.dot`` file, showing all dependencies in the project
-* a ``foo.dot.<target>`` file for each target, showing on which other targets
-  it depends
-* a ``foo.dot.<target>.dependers`` file for each target, showing which other
-  targets depend on it
-
-Those .dot files can be converted to images using the *dot* command from the
-Graphviz package:
-
-.. code-block:: shell
-
-  dot -Tpng -o foo.png foo.dot
-
-.. versionadded:: 3.10
-  The different dependency types ``PUBLIC``, ``INTERFACE`` and ``PRIVATE``
-  are represented as solid, dashed and dotted edges.
-
-Variables specific to the Graphviz support
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The resulting graphs can be huge.  The look and content of the generated graphs
-can be controlled using the file ``CMakeGraphVizOptions.cmake``.  This file is
-first searched in :variable:`CMAKE_BINARY_DIR`, and then in
-:variable:`CMAKE_SOURCE_DIR`.  If found, the variables set in it are used to
-adjust options for the generated Graphviz files.
-
-.. variable:: GRAPHVIZ_GRAPH_NAME
-
- The graph name.
-
- * Mandatory: NO
- * Default: value of :variable:`CMAKE_PROJECT_NAME`
-
-.. variable:: GRAPHVIZ_GRAPH_HEADER
-
- The header written at the top of the Graphviz files.
-
- * Mandatory: NO
- * Default: "node [ fontsize = "12" ];"
-
-.. variable:: GRAPHVIZ_NODE_PREFIX
-
- The prefix for each node in the Graphviz files.
-
- * Mandatory: NO
- * Default: "node"
-
-.. variable:: GRAPHVIZ_EXECUTABLES
-
- Set to FALSE to exclude executables from the generated graphs.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_STATIC_LIBS
-
- Set to FALSE to exclude static libraries from the generated graphs.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_SHARED_LIBS
-
- Set to FALSE to exclude shared libraries from the generated graphs.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_MODULE_LIBS
-
- Set to FALSE to exclude module libraries from the generated graphs.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_INTERFACE_LIBS
-
- Set to FALSE to exclude interface libraries from the generated graphs.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_OBJECT_LIBS
-
- Set to FALSE to exclude object libraries from the generated graphs.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_UNKNOWN_LIBS
-
- Set to FALSE to exclude unknown libraries from the generated graphs.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_EXTERNAL_LIBS
-
- Set to FALSE to exclude external libraries from the generated graphs.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_CUSTOM_TARGETS
-
- Set to TRUE to include custom targets in the generated graphs.
-
- * Mandatory: NO
- * Default: FALSE
-
-.. variable:: GRAPHVIZ_IGNORE_TARGETS
-
- A list of regular expressions for names of targets to exclude from the
- generated graphs.
-
- * Mandatory: NO
- * Default: empty
-
-.. variable:: GRAPHVIZ_GENERATE_PER_TARGET
-
- Set to FALSE to not generate per-target graphs ``foo.dot.<target>``.
-
- * Mandatory: NO
- * Default: TRUE
-
-.. variable:: GRAPHVIZ_GENERATE_DEPENDERS
-
- Set to FALSE to not generate depender graphs ``foo.dot.<target>.dependers``.
-
- * Mandatory: NO
- * Default: TRUE
+  This module is not intended to be included in CMake projects directly.
+  It once contained the information for using Graphviz in CMake.  For
+  Graphviz usage in CMake refer to the :option:`cmake --graphviz`.
 #]=======================================================================]
diff --git a/Modules/CMakeVerifyManifest.cmake b/Modules/CMakeVerifyManifest.cmake
index d98a49e..5333869 100644
--- a/Modules/CMakeVerifyManifest.cmake
+++ b/Modules/CMakeVerifyManifest.cmake
@@ -5,31 +5,53 @@
 CMakeVerifyManifest
 -------------------
 
-Use this script to verify that embedded manifests and side-by-side
-manifests for a project match.
+This module is intended to be used in command-line mode using the
+:ref:`cmake -P <Script Processing Mode>` to verify that embedded manifests
+and side-by-side manifests for a project match.
 
-This script first recursively globs ``*.manifest`` files from
-the current directory and creates a list of allowed version.
-Additional versions can be passed by setting ``allow_versions``
-from the invocation command.
-Next, the script globs ``*.exe`` and ``*.dll`` files.  Each
+Load this module in a CMake script with:
+
+.. code-block:: cmake
+
+  include(CMakeVerifyManifest)
+
+This module first recursively globs ``*.manifest`` files from
+the current source directory and creates a list of allowed versions.
+
+Next, the script globs all ``*.exe`` and ``*.dll`` files.  Each
 ``.exe`` and ``.dll`` file is scanned for embedded manifests and
 the versions of CRT are checked to be in the list of allowed
-version.
+versions.
 
-Example
-^^^^^^^
+Input Variables
+^^^^^^^^^^^^^^^
 
-To run this script, navigate to a directory and run the script
-with ``cmake -P``.
+This module accepts the following variables:
 
-::
+``allow_versions``
+  Additional versions can be passed by setting the ``allow_versions``
+  variable from the invocation command.  This enables using additional
+  embedded manifest versions in a project, even if that version was not
+  found in a ``.manifest`` file.
 
-  cmake -Dallow_versions=8.0.50608.0 -PCMakeVerifyManifest.cmake
+Examples
+^^^^^^^^
 
-This call allows an embedded manifest of 8.0.50608.0 to be used
-in a project, even if that version was not found in a
-``.manifest`` file.
+To use this module in the project, create a local command-line script (for
+example, in the project's subdirectory ``cmake/scripts``) and include the
+module:
+
+.. code-block:: cmake
+  :caption: ``cmake/scripts/verify-manifest.cmake``
+
+  include(CMakeVerifyManifest)
+
+Then run the local script in command-line and, for example, specify
+additional embedded manifest of ``8.0.50608.0`` to be used in a project:
+
+.. code-block:: shell
+
+  cmake -Dallow_versions=8.0.50608.0 -Pcmake/scripts/verify-manifest.cmake
 #]=======================================================================]
 
 # crt_version:
diff --git a/Modules/CTestScriptMode.cmake b/Modules/CTestScriptMode.cmake
index d5dbddb..b8f98b4 100644
--- a/Modules/CTestScriptMode.cmake
+++ b/Modules/CTestScriptMode.cmake
@@ -5,9 +5,11 @@
 CTestScriptMode
 ---------------
 
+.. note::
 
-
-This file is read by ctest in script mode (-S)
+  This module is not intended to be included or invoked directly by project
+  code.  It is internally used by CTest running in script mode (-S) to
+  determine current system.  For usage details refer to the :option:`ctest -S`.
 #]=======================================================================]
 
 # Determine the current system, so this information can be used
diff --git a/Modules/CTestUseLaunchers.cmake b/Modules/CTestUseLaunchers.cmake
index dc015f8..c26c840 100644
--- a/Modules/CTestUseLaunchers.cmake
+++ b/Modules/CTestUseLaunchers.cmake
@@ -60,7 +60,7 @@
 
 if(CTEST_USE_LAUNCHERS)
   set(__launch_common_options
-    "--target-name <TARGET_NAME> --current-build-dir <CMAKE_CURRENT_BINARY_DIR>")
+    "--target-name <TARGET_NAME> --current-build-dir <CMAKE_CURRENT_BINARY_DIR> --build-dir <CMAKE_BINARY_DIR> --object-dir <TARGET_SUPPORT_DIR>")
 
   set(__launch_compile_options
     "${__launch_common_options} --output <OBJECT> --source <SOURCE> --language <LANGUAGE>")
diff --git a/Modules/CheckPIESupported.cmake b/Modules/CheckPIESupported.cmake
index 592612c..b4d47f9 100644
--- a/Modules/CheckPIESupported.cmake
+++ b/Modules/CheckPIESupported.cmake
@@ -7,23 +7,36 @@
 
 .. versionadded:: 3.14
 
-This module provides the ``check_pie_supported()`` function to check whether the
-linker supports Position Independent Code (PIE) or No Position Independent Code
-(NO_PIE) for executables.
+This module provides a command to check whether the linker supports Position
+Independent Code (PIE) or No Position Independent Code (NO_PIE) for
+executables.
+
+Load this module in a CMake project with:
+
+.. code-block:: cmake
+
+  include(CheckPIESupported)
 
 When setting the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property,
 PIC-related compile and link options are added when building library objects,
 and PIE-related compile options are added when building objects of executable
 targets, regardless of this module.  Use this module to ensure that the
-``POSITION_INDEPENDENT_CODE`` target property for executables is also honored at
-link time.
+``POSITION_INDEPENDENT_CODE`` target property for executables is also honored
+at link time.
+
+Commands
+^^^^^^^^
+
+This module provides the following command:
 
 .. command:: check_pie_supported
 
+  Checks for PIE/NO_PIE support and prepares all executables to have link
+  time PIE options enabled:
+
   .. code-block:: cmake
 
-    check_pie_supported([OUTPUT_VARIABLE <output>]
-                        [LANGUAGES <lang>...])
+    check_pie_supported([OUTPUT_VARIABLE <output>] [LANGUAGES <langs>...])
 
   Options are:
 
@@ -32,7 +45,7 @@
     bypassed because it uses cached results from a previous call, the output
     will be empty even if errors were present in the previous call.
 
-  ``LANGUAGES <lang>...``
+  ``LANGUAGES <langs>...``
     Check the linkers used for each of the specified languages.
     If this option is not provided, the command checks all enabled languages.
 
@@ -50,13 +63,13 @@
 Variables
 ^^^^^^^^^
 
-For each language checked, the ``check_pie_supported()`` function defines two
+For each language checked, the ``check_pie_supported()`` command defines two
 boolean cache variables:
 
- ``CMAKE_<lang>_LINK_PIE_SUPPORTED``
-   Set to true if ``PIE`` is supported by the linker and false otherwise.
- ``CMAKE_<lang>_LINK_NO_PIE_SUPPORTED``
-   Set to true if ``NO_PIE`` is supported by the linker and false otherwise.
+``CMAKE_<lang>_LINK_PIE_SUPPORTED``
+  Set to true if ``PIE`` is supported by the linker and false otherwise.
+``CMAKE_<lang>_LINK_NO_PIE_SUPPORTED``
+  Set to true if ``NO_PIE`` is supported by the linker and false otherwise.
 
 Examples
 ^^^^^^^^
@@ -82,11 +95,17 @@
 
   add_executable(foo ...)
 
+  message(CHECK_START "Checking for C linker PIE support")
+
   include(CheckPIESupported)
   check_pie_supported(OUTPUT_VARIABLE output LANGUAGES C)
   set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
-  if(NOT CMAKE_C_LINK_PIE_SUPPORTED)
-    message(WARNING "PIE is not supported at link time:\n${output}"
+
+  if(CMAKE_C_LINK_PIE_SUPPORTED)
+    message(CHECK_PASS "yes")
+  else()
+    message(CHECK_FAIL "no")
+    message(VERBOSE "PIE is not supported at link time:\n${output}"
                     "PIE link options will not be passed to linker.")
   endif()
 
@@ -98,7 +117,6 @@
 
   add_executable(foo ...)
   set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE TRUE)
-
 #]=======================================================================]
 
 
diff --git a/Modules/Compiler/MSVC-C.cmake b/Modules/Compiler/MSVC-C.cmake
index 7de6039..85ceae8 100644
--- a/Modules/Compiler/MSVC-C.cmake
+++ b/Modules/Compiler/MSVC-C.cmake
@@ -33,6 +33,16 @@
     endmacro()
   endif()
 
+  if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.39)
+    # VS 17.10 did not have a "stdclatest" value for LanguageStandard_C.
+    if(NOT CMAKE_GENERATOR MATCHES "Visual Studio"
+        OR CMAKE_VS_VERSION_BUILD_NUMBER VERSION_GREATER_EQUAL 17.11)
+      set(CMAKE_C23_STANDARD_COMPILE_OPTION "-std:clatest")
+      set(CMAKE_C23_EXTENSION_COMPILE_OPTION "-std:clatest")
+      set(CMAKE_C_STANDARD_LATEST 23)
+    endif()
+  endif()
+
   __compiler_check_default_language_standard(C 19.27 99)
 else()
   # MSVC has no specific options to set C language standards, but set them as
diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake
index 61e2ea5..b314bcc 100644
--- a/Modules/ExternalProject.cmake
+++ b/Modules/ExternalProject.cmake
@@ -654,6 +654,48 @@
   examples of build systems whose build step is smart enough to know if the
   configure step needs to be rerun.
 
+``CONFIGURE_ENVIRONMENT_MODIFICATION <modification>...``
+  .. versionadded: 4.2
+
+  Specify environment variables that should be modified for the configure step.
+
+  Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
+  variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
+  case-sensitive name of an environment variable to be modified.  Entries are
+  considered in the order specified in the property's value. The ``OP`` may be
+  one of:
+
+  .. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
+
+  .. code-block:: cmake
+
+    ExternalProject_Add(example
+      ... # Download options, etc...
+      CONFIGURE_ENVIRONMENT_MODIFICATION
+        SDKROOT=set:macosx
+        PKG_CONFIG_PATH=set:$ENV{PKG_CONFIG_PATH}
+    )
+
+  This snippet defines two environment variables when configuring the example
+  project. The ``SDKROOT`` environment variable is set to ``macosx`, while
+  the value of ``PKG_CONFIG_PATH`` is forwarded to the external project.
+
+  Environment modifications work with ``LIST_SEPARATOR`` to replace the
+  separator with a ``;`` in the environment variable.
+
+  .. code-block:: cmake
+
+    ExternalProject_Add(example
+      ... # Download options, etc...
+      LIST_SEPARATOR ,
+      CONFIGURE_ENVIRONMENT_MODIFICATION
+        LIST_VAR=set:a,b,c
+    )
+
+  This snippet
+  and the environment variable ``LIST_VAR`` is passed to the configure command
+  invocation with the value ``a;b;c``.
+
 Build Step Options
 """"""""""""""""""
 
@@ -719,6 +761,19 @@
   ``JOB_SERVER_AWARE`` option for details.  This option is relevant
   only when an explicit ``BUILD_COMMAND`` is specified.
 
+``BUILD_ENVIRONMENT_MODIFICATION <modification>...``
+  .. versionadded: 4.2
+
+  Specify environment variables that should be modified for the build step.
+
+  Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
+  variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
+  case-sensitive name of an environment variable to be modified.  Entries are
+  considered in the order specified in the property's value. The ``OP`` may be
+  one of:
+
+  .. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
+
 Install Step Options
 """"""""""""""""""""
 
@@ -777,6 +832,19 @@
   :envvar:`CMAKE_INSTALL_MODE` environment variable changes from one run
   to another.
 
+``INSTALL_ENVIRONMENT_MODIFICATION <modification>...``
+  .. versionadded: 4.2
+
+  Specify environment variables that should be modified for the install step.
+
+  Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
+  variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
+  case-sensitive name of an environment variable to be modified.  Entries are
+  considered in the order specified in the property's value. The ``OP`` may be
+  one of:
+
+  .. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
+
 Test Step Options
 """""""""""""""""
 
@@ -815,6 +883,19 @@
   This may cause a step target to be created automatically for either
   the ``install`` or ``build`` step.  See policy :policy:`CMP0114`.
 
+``TEST_ENVIRONMENT_MODIFICATION <modification>...``
+  .. versionadded: 4.2
+
+  Specify environment variables that should be modified for the test step.
+
+  Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
+  variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
+  case-sensitive name of an environment variable to be modified.  Entries are
+  considered in the order specified in the property's value. The ``OP`` may be
+  one of:
+
+  .. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
+
 Output Logging Options
 """"""""""""""""""""""
 
@@ -940,7 +1021,8 @@
 """""""""""""""""""""
 
 ``LIST_SEPARATOR <sep>``
-  For any of the various ``..._COMMAND`` options, and ``CMAKE_ARGS``,
+  For any of the various ``..._COMMAND`` options, ``CMAKE_ARGS``, and
+  `..._ENVIRONMENT_MODIFICATION`` operations,
   ``ExternalProject`` will replace ``<sep>`` with ``;`` in the specified
   command lines. This can be used to ensure a command has a literal ``;`` in it
   where direct usage would otherwise be interpreted as argument separators to
@@ -1043,6 +1125,20 @@
   ``DEPENDS <file>...``
     Files on which this custom step depends.
 
+  ``ENVIRONMENT_MODIFICATION <modification>...``
+    .. versionadded: 4.2
+
+    Specify environment variables that should be modified while running the
+    commands in the external project step.
+
+    Set a :ref:`semicolon-separated list <CMake Language Lists>` of environment
+    variables and values of the form ``MYVAR=OP:VALUE``, where ``MYVAR`` is the
+    case-sensitive name of an environment variable to be modified.  Entries are
+    considered in the order specified in the property's value. The ``OP`` may be
+    one of:
+
+    .. include:: ../include/ENVIRONMENT_MODIFICATION_OPS.rst
+
   ``INDEPENDENT <bool>``
     .. versionadded:: 3.19
 
@@ -2057,6 +2153,7 @@
     DEPENDEES
     DEPENDERS
     DEPENDS
+    ENVIRONMENT_MODIFICATION
     INDEPENDENT
     BYPRODUCTS
     ALWAYS
@@ -2176,6 +2273,53 @@
     string(REPLACE "${sep}" "\\;" command "${command}")
   endif()
 
+  # Add environment here!
+  get_property(environment
+    TARGET ${name}
+    PROPERTY _EP_${step}_ENVIRONMENT_MODIFICATION)
+  if(environment AND command)
+    if("${sep}" STREQUAL ":")
+      # The environment modification operation and value is separated by a
+      # colon. We should not replace that colon with a semicolon, allowing
+      # colons to act as a valid list separator.
+      # <name>=<op>:<value>
+      # Note: Environment variable names can contain `:` on Windows
+      set(result "")
+      foreach(env_modification IN LISTS environment)
+        if("${env_modification}" MATCHES "(.*)=([a-z]*):(.*)?")
+          if(CMAKE_MATCH_COUNT EQUAL 3)
+            string(REPLACE "${sep}" "\\\\\\\\\\;" _escapedMod "${CMAKE_MATCH_3}")
+          endif()
+          list(APPEND result "${CMAKE_MATCH_1}=${CMAKE_MATCH_2}:${_escapedMod}")
+        else()
+          message(SEND_ERROR "Malformed environment modification specifier:"
+          " '${env_modification}'\n"
+          "Expected MYVAR=OP:VALUE")
+        endif()
+      endforeach()
+      set(environment ${result})
+    elseif(sep)
+      # if the separator is not a colon, we don't have to worry about
+      # accidentally replacing the separator between the modification and value
+      string(REPLACE "${sep}" "\\\\\\\\;" environment "${environment}")
+    endif()
+    list(JOIN environment ";--modify;" environment)
+    list(PREPEND environment "--modify")
+
+    string(REPLACE ";" "\;" command "${command}")
+    string(REPLACE "COMMAND" ";" command "${command}")
+
+    set(__cmd)
+    foreach(__item IN LISTS command)
+      list(APPEND __cmd "COMMAND")
+      if(__item AND NOT "x${__item}" STREQUAL "x;;")
+        list(APPEND __cmd "${CMAKE_COMMAND}" -E env ${environment} --)
+      endif()
+      list(APPEND __cmd "${__item}")
+    endforeach()
+    set(command ${__cmd})
+  endif()
+
   # Replace location tags.
   _ep_replace_location_tags(
     ${name}
@@ -2660,6 +2804,14 @@
     set(dependees patch)
   endif()
 
+  get_property(environment
+    TARGET ${name}
+    PROPERTY _EP_CONFIGURE_ENVIRONMENT_MODIFICATION
+  )
+  if(environment)
+    set(environment "ENVIRONMENT_MODIFICATION" ${environment})
+  endif()
+
   get_property(log
     TARGET ${name}
     PROPERTY _EP_LOG_CONFIGURE
@@ -2691,6 +2843,7 @@
       WORKING_DIRECTORY \${binary_dir}
       DEPENDEES \${dependees}
       DEPENDS \${file_deps}
+      ${environment}
       ${log}
       ${uses_terminal}
     )"
@@ -2770,6 +2923,13 @@
     set(maybe_JOB_SERVER_AWARE "")
   endif()
 
+  get_property(environment
+    TARGET ${name}
+    PROPERTY _EP_BUILD_ENVIRONMENT_MODIFICATION
+  )
+  if(environment)
+    set(environment ENVIRONMENT_MODIFICATION ${environment})
+  endif()
 
   set(__cmdQuoted)
   foreach(__item IN LISTS cmd)
@@ -2785,6 +2945,7 @@
       DEPENDS \${file_deps}
       ALWAYS \${always}
       ${maybe_JOB_SERVER_AWARE}
+      ${environment}
       ${log}
       ${uses_terminal}
     )"
@@ -2857,6 +3018,14 @@
     set(maybe_JOB_SERVER_AWARE "")
   endif()
 
+  get_property(environment
+    TARGET ${name}
+    PROPERTY _EP_INSTALL_ENVIRONMENT_MODIFICATION
+  )
+  if(environment)
+    set(environment ENVIRONMENT_MODIFICATION ${environment})
+  endif()
+
   set(__cmdQuoted)
   foreach(__item IN LISTS cmd)
     string(APPEND __cmdQuoted " [==[${__item}]==]")
@@ -2870,6 +3039,7 @@
       DEPENDEES build
       ALWAYS \${always}
       ${maybe_JOB_SERVER_AWARE}
+      ${environment}
       ${log}
       ${uses_terminal}
     )"
@@ -2936,6 +3106,14 @@
       set(uses_terminal "")
     endif()
 
+    get_property(environment
+      TARGET ${name}
+      PROPERTY _EP_TEST_ENVIRONMENT_MODIFICATION
+    )
+    if(environment)
+      set(environment ENVIRONMENT_MODIFICATION ${environment})
+    endif()
+
     set(__cmdQuoted)
     foreach(__item IN LISTS cmd)
       string(APPEND __cmdQuoted " [==[${__item}]==]")
@@ -2948,6 +3126,7 @@
         ${dependees_args}
         ${dependers_args}
         ${exclude_args}
+        ${environment}
         ${log}
         ${uses_terminal}
       )"
diff --git a/Modules/ExternalProject/shared_internal_commands.cmake b/Modules/ExternalProject/shared_internal_commands.cmake
index cb7b772..c2e5b47 100644
--- a/Modules/ExternalProject/shared_internal_commands.cmake
+++ b/Modules/ExternalProject/shared_internal_commands.cmake
@@ -1896,6 +1896,7 @@
     # Configure step options
     #
     CONFIGURE_COMMAND
+    CONFIGURE_ENVIRONMENT_MODIFICATION
     CMAKE_COMMAND
     CMAKE_GENERATOR
     CMAKE_GENERATOR_PLATFORM
@@ -1910,6 +1911,7 @@
     # Build step options
     #
     BUILD_COMMAND
+    BUILD_ENVIRONMENT_MODIFICATION
     BUILD_IN_SOURCE
     BUILD_ALWAYS
     BUILD_BYPRODUCTS
@@ -1918,12 +1920,14 @@
     # Install step options
     #
     INSTALL_COMMAND
+    INSTALL_ENVIRONMENT_MODIFICATION
     INSTALL_BYPRODUCTS
     INSTALL_JOB_SERVER_AWARE
     #
     # Test step options
     #
     TEST_COMMAND
+    TEST_ENVIRONMENT_MODIFICATION
     TEST_BEFORE_INSTALL
     TEST_AFTER_INSTALL
     TEST_EXCLUDE_FROM_MAIN
diff --git a/Modules/FeatureSummary.cmake b/Modules/FeatureSummary.cmake
index c4b27da..6b83903 100644
--- a/Modules/FeatureSummary.cmake
+++ b/Modules/FeatureSummary.cmake
@@ -7,32 +7,45 @@
 FeatureSummary
 --------------
 
-Functions for generating a summary of enabled/disabled features.
+.. only:: html
 
-These functions can be used to generate a summary of enabled and disabled
-packages and/or features for a build tree such as::
+   .. contents::
 
-    -- The following features have been enabled:
+This module provides commands for generating a summary of enabled/disabled
+features.
 
-     * Example, usage example
+Load this module in CMake with:
 
-    -- The following OPTIONAL packages have been found:
+.. code-block:: cmake
 
-     * LibXml2 (required version >= 2.4), XML library, <http://xmlsoft.org>
-       Enables HTML-import in MyWordProcessor
-       Enables odt-export in MyWordProcessor
-     * PNG, image library, <http://www.libpng.org/pub/png/>
-       Enables saving screenshots
+  include(FeatureSummary)
 
-    -- The following OPTIONAL packages have not been found:
+Commands provided by this module can be used to generate a summary of enabled
+and disabled packages and/or features for a build tree such as::
 
-     * Lua, the Lua scripting language, <https://www.lua.org>
-       Enables macros in MyWordProcessor
-     * OpenGL, Open Graphics Library
+  -- The following features have been enabled:
+
+   * Example, usage example
+
+  -- The following OPTIONAL packages have been found:
+
+   * LibXml2 (required version >= 2.4), XML library, <http://xmlsoft.org>
+     Enables HTML-import in MyWordProcessor
+     Enables odt-export in MyWordProcessor
+   * PNG, image library, <http://www.libpng.org/pub/png/>
+     Enables saving screenshots
+
+  -- The following OPTIONAL packages have not been found:
+
+   * Lua, the Lua scripting language, <https://www.lua.org>
+     Enables macros in MyWordProcessor
+   * OpenGL, Open Graphics Library
 
 Global Properties
 ^^^^^^^^^^^^^^^^^
 
+The following global properties are used by this module:
+
 .. variable:: FeatureSummary_PKG_TYPES
 
   .. versionadded:: 3.8
@@ -69,8 +82,9 @@
 
   This global property defines the default package type.
 
-  When the :command:`feature_summary()` command is called, and the user has not
-  explicitly set a type of some package, its type will be set to this value.
+  When the :command:`feature_summary()` command is called, and the user has
+  not explicitly set a type of some package, its type will be set to the
+  value of this property.
 
   This value must be one of the types defined in the
   :variable:`FeatureSummary_PKG_TYPES` global property.
@@ -88,6 +102,519 @@
       The following <FeatureSummary_<TYPE>_DESCRIPTION> have been found:
 
   If not set, default string ``<TYPE> packages`` is used.
+
+Commands
+^^^^^^^^
+
+This module provides the following commands:
+
+* :command:`feature_summary`
+* :command:`set_package_properties`
+* :command:`add_feature_info`
+
+Printing Feature Summary
+""""""""""""""""""""""""
+
+.. command:: feature_summary
+
+  Prints information about enabled or disabled packages and features of a
+  project:
+
+  .. code-block:: cmake
+
+    feature_summary(
+      WHAT (ALL
+        | PACKAGES_FOUND | PACKAGES_NOT_FOUND
+        | <TYPE>_PACKAGES_FOUND | <TYPE>_PACKAGES_NOT_FOUND
+        | ENABLED_FEATURES | DISABLED_FEATURES)
+      [FILENAME <file>]
+      [APPEND]
+      [VAR <variable-name>]
+      [INCLUDE_QUIET_PACKAGES]
+      [FATAL_ON_MISSING_REQUIRED_PACKAGES]
+      [DESCRIPTION <description> | DEFAULT_DESCRIPTION]
+      [QUIET_ON_EMPTY]
+    )
+
+  This command can be used to print information about enabled or disabled
+  packages and features of a project.  By default, only the names of the
+  features/packages will be printed and their required version when one was
+  specified.  Use :command:`set_package_properties()` to add more useful
+  information, e.g., a homepage URL for the respective package or their
+  purpose in the project.
+
+  .. rubric:: The arguments are:
+
+  ``WHAT``
+    This is the only mandatory option.  It specifies what information will be
+    printed:
+
+    ``ALL``
+      Print everything.
+    ``ENABLED_FEATURES``
+      The list of all features which are enabled.
+    ``DISABLED_FEATURES``
+      The list of all features which are disabled.
+    ``PACKAGES_FOUND``
+      The list of all packages which have been found.
+    ``PACKAGES_NOT_FOUND``
+      The list of all packages which have not been found.
+
+    For each package type ``<TYPE>`` defined by the
+    :variable:`FeatureSummary_PKG_TYPES` global property, the following
+    information can also be used:
+
+    ``<TYPE>_PACKAGES_FOUND``
+      The list of only packages of type ``<TYPE>`` which have been found.
+    ``<TYPE>_PACKAGES_NOT_FOUND``
+      The list of only packages of type ``<TYPE>`` which have not been found.
+
+    .. versionchanged:: 3.1
+      The ``WHAT`` option is now a multi-value keyword, so that these values can
+      be combined, with the exception of the ``ALL`` value, in order to
+      customize the output.  For example:
+
+    .. code-block:: cmake
+
+      feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES)
+
+  ``FILENAME <file>``
+    If this option is given, the information is printed into this file instead
+    of the terminal.  Relative ``<file>`` path is interpreted as being relative
+    to the current source directory (i.e. :variable:`CMAKE_CURRENT_SOURCE_DIR`).
+
+  ``APPEND``
+    If this option is given, the output is appended to the ``<file>`` provided
+    by the ``FILENAME`` option, otherwise the file is overwritten if it already
+    exists.
+
+  ``VAR <variable-name>``
+    If this option is given, the information is stored into the specified
+    variable ``<variable-name>`` instead of the terminal.
+
+  ``INCLUDE_QUIET_PACKAGES``
+    If this option is given, packages which have been searched with
+    :command:`find_package(... QUIET)` will also be listed.  By default they are
+    skipped.
+
+  ``FATAL_ON_MISSING_REQUIRED_PACKAGES``
+    If this option is given, CMake will abort with fatal error if a package
+    which is marked as one of the package types listed in the
+    :variable:`FeatureSummary_REQUIRED_PKG_TYPES` global property has not been
+    found.
+
+  ``DESCRIPTION <description>``
+    A description or headline which will be printed above the actual content.
+    Without this option, if only one package type was requested, no title is
+    printed, unless a custom string is explicitly set using this option or
+    ``DEFAULT_DESCRIPTION`` option is used that outputs a default title for the
+    requested type.
+
+  ``DEFAULT_DESCRIPTION``
+    .. versionadded:: 3.9
+
+    The default description or headline to be printed above the content as
+    opposed to the customizable ``DESCRIPTION <description>``.
+
+  ``QUIET_ON_EMPTY``
+    .. versionadded:: 3.8
+
+    If this option is given, when only one package type was requested, and no
+    packages belonging to that category were found, then no output (including
+    the ``DESCRIPTION``) is printed nor added to the ``FILENAME``, or the
+    ``VAR`` variable.
+
+Package Properties
+""""""""""""""""""
+
+.. command:: set_package_properties
+
+  Sets package properties:
+
+  .. code-block:: cmake
+
+    set_package_properties(
+      <PackageName>
+      PROPERTIES
+        [URL <url>]
+        [DESCRIPTION <description>]
+        [TYPE (RUNTIME|OPTIONAL|RECOMMENDED|REQUIRED)]
+        [PURPOSE <purpose>]
+    )
+
+  Use this command to configure and provide information about the package
+  named ``<PackageName>``, which can then be displayed using the
+  :command:`feature_summary()` command.  This command can be called either
+  directly within the corresponding :ref:`Find module <Find Modules>` or in
+  the project that uses the module after invoking the :command:`find_package()`
+  call.  The features for which information can be set are determined
+  automatically after the :command:`find_package()` command.
+
+  .. rubric:: The arguments are:
+
+  ``<PackageName>``
+    The name of the package.  For example, as specified in the
+    :command:`find_package(<PackageName>)` argument.
+
+  ``PROPERTIES``
+    Specifies the properties to set:
+
+    ``URL <url>``
+      This should be the homepage of the package, or something similar.
+      Ideally this is set already directly in the
+      :ref:`Find module <Find Modules>`.
+
+    ``DESCRIPTION <description>``
+      A short description what that package is, at most one sentence.
+      Ideally this is set already directly in the
+      :ref:`Find module <Find Modules>`.
+
+    ``TYPE <type>``
+      What type of dependency has the using project on that package.
+
+      Default ``<type>`` is ``OPTIONAL``.  In this case it is a package
+      which can be used by the project when available at buildtime, but the
+      project also works without it.
+
+      ``RECOMMENDED`` package type is similar to ``OPTIONAL``, i.e.  the
+      project will build if the package is not present, but the
+      functionality of the resulting binaries will be severely limited.  If
+      a ``REQUIRED`` package is not available at buildtime, the project may
+      not even build. This can be combined with the
+      :command:`feature_summary(FATAL_ON_MISSING_REQUIRED_PACKAGES)` command
+      option.
+
+      Last, a ``RUNTIME`` package is a package which is actually not used
+      at all during the build, but which is required for actually running
+      the resulting binaries.  So if such a package is missing, the project
+      can still be built, but it may not work later on.
+
+      If ``set_package_properties()`` is called multiple times for the same
+      package with different TYPEs, the ``TYPE`` is only changed to higher
+      TYPEs (``RUNTIME < OPTIONAL < RECOMMENDED < REQUIRED``), lower TYPEs
+      are ignored.  The ``TYPE`` property is project-specific, so it cannot
+      be set by the :ref:`Find module <Find Modules>`, but must be set in
+      the project.
+
+      The accepted types can be changed by setting the
+      :variable:`FeatureSummary_PKG_TYPES` global property.
+
+    ``PURPOSE <purpose>``
+      This describes which features this package enables in the project,
+      i.e.  it tells the user what functionality they get in the resulting
+      binaries.  If ``set_package_properties()`` is called multiple times
+      for a package, all ``PURPOSE`` properties are appended to a list of
+      purposes of the package in the project.  As the ``TYPE`` property,
+      also the ``PURPOSE`` property is project-specific, so it cannot be
+      set by the :ref:`Find module <Find Modules>`, but must be set in the
+      project.
+
+Adding Feature Info
+"""""""""""""""""""
+
+.. command:: add_feature_info
+
+  Adds feature information:
+
+  .. code-block:: cmake
+
+    add_feature_info(<name> <condition> <description>)
+
+  Use this command to add information about a feature identified with a given
+  ``<name>``.
+
+  .. rubric:: The arguments are:
+
+  ``<name>``
+    Identification name for a feature being added.
+
+  ``<condition>``
+    Specifies the conditions that determine whether this feature is enabled
+    or disabled.
+
+    The ``<condition>`` argument can be:
+
+    * A single condition (such as a variable name).
+
+    * .. versionadded:: 3.8
+        A :ref:`semicolon-separated list <CMake Language Lists>` of multiple
+        conditions.
+
+    * .. versionadded:: 4.0
+        A full :ref:`Condition Syntax` as used in an ``if(<condition>)``
+        clause.  See policy :policy:`CMP0183`.  This enables using entire
+        condition syntax (such as grouping conditions with parens and
+        similar).
+
+  ``<description>``
+    A text describing the feature.  This information can be displayed using
+    :command:`feature_summary()` for ``ENABLED_FEATURES`` and
+    ``DISABLED_FEATURES`` respectively.
+
+Deprecated Commands
+"""""""""""""""""""
+
+The following legacy and deprecated commands are provided for backward
+compatibility with previous CMake versions:
+
+.. command:: set_package_info
+
+  .. deprecated:: 3.8
+    Use the :command:`set_package_properties`, and :command:`add_feature_info`
+    commands instead.
+
+  Sets up information about the specified package, which can then be displayed
+  via :command:`feature_summary()`:
+
+  .. code-block:: cmake
+
+    set_package_info(<PackageName> <description> [<url> [<purpose>]])
+
+  ``<PackageName>``
+    Name of the package.
+
+  ``<description>``
+    A short description of the package.
+
+  ``<url>``
+    Homepage of the package.
+
+  ``<purpose>``
+    The purpose of the package.
+
+  This command can be used either directly in the
+  :ref:`Find module <Find Modules>` or in the project which uses the
+  ``FeatureSummary`` module after the :command:`find_package()` call.  The
+  features for which information can be set are added automatically by the
+  ``find_package()`` command.
+
+.. command:: set_feature_info
+
+  .. deprecated:: 3.8
+
+  Sets feature info for a package:
+
+  .. code-block:: cmake
+
+    set_feature_info(<name> <description> [<url>])
+
+  Does the same as:
+
+  .. code-block:: cmake
+
+    set_package_info(<name> <description> [<url>])
+
+.. command:: print_enabled_features
+
+  .. deprecated:: 3.8
+
+  Prints enabled features:
+
+  .. code-block:: cmake
+
+    print_enabled_features()
+
+  Does the same as:
+
+  .. code-block:: cmake
+
+    feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:")
+
+.. command:: print_disabled_features
+
+  .. deprecated:: 3.8
+
+  Prints disabled features:
+
+  .. code-block:: cmake
+
+    print_disabled_features()
+
+  Does the same as:
+
+  .. code-block:: cmake
+
+    feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
+
+Examples
+^^^^^^^^
+
+Example: Appending Feature Summary to a File
+""""""""""""""""""""""""""""""""""""""""""""
+
+In the following example, the feature summary output will be appended to
+a specified file instead of printing:
+
+.. code-block:: cmake
+
+  include(FeatureSummary)
+  feature_summary(WHAT ALL FILENAME ${CMAKE_BINARY_DIR}/all.log APPEND)
+
+Example: Storing Feature Summary in a Variable
+""""""""""""""""""""""""""""""""""""""""""""""
+
+In the following example, the feature summary of enabled features is stored
+in a specified variable ``enabledFeaturesText``, including the ``QUIET``
+packages:
+
+.. code-block:: cmake
+
+  include(FeatureSummary)
+
+  feature_summary(
+    WHAT ENABLED_FEATURES
+    INCLUDE_QUIET_PACKAGES
+    DESCRIPTION "Enabled Features:"
+    VAR enabledFeaturesText
+  )
+
+  message(STATUS "${enabledFeaturesText}")
+
+Example: Adding a Custom Package Type
+"""""""""""""""""""""""""""""""""""""
+
+In the following example a custom package type is added and printed only
+the categories that are not empty:
+
+.. code-block:: cmake
+
+  include(FeatureSummary)
+
+  set_property(GLOBAL APPEND PROPERTY FeatureSummary_PKG_TYPES BUILD)
+
+  find_package(FOO)
+  set_package_properties(FOO PROPERTIES TYPE BUILD)
+
+  feature_summary(
+    WHAT BUILD_PACKAGES_FOUND
+    DESCRIPTION "Build tools found:"
+    QUIET_ON_EMPTY
+  )
+
+  feature_summary(
+    WHAT BUILD_PACKAGES_NOT_FOUND
+    DESCRIPTION "Build tools not found:"
+    QUIET_ON_EMPTY
+  )
+
+Example: Setting Package Info
+"""""""""""""""""""""""""""""
+
+Example for setting the info for a package:
+
+.. code-block:: cmake
+
+  include(FeatureSummary)
+
+  find_package(LibXml2)
+  set_package_properties(
+    LibXml2
+    PROPERTIES
+      DESCRIPTION "XML library"
+      URL "http://xmlsoft.org"
+  )
+  # or
+  set_package_properties(
+    LibXml2
+    PROPERTIES
+      TYPE RECOMMENDED
+      PURPOSE "Enables HTML-import in MyWordProcessor"
+  )
+  # or
+  set_package_properties(
+    LibXml2
+    PROPERTIES
+      TYPE OPTIONAL
+      PURPOSE "Enables odt-export in MyWordProcessor"
+  )
+
+  find_package(DBUS)
+  set_package_properties(
+    DBUS
+    PROPERTIES
+      TYPE RUNTIME
+      PURPOSE "Necessary to disable the screensaver during a presentation"
+  )
+
+Example: Printing Feature Summary
+"""""""""""""""""""""""""""""""""
+
+In the following example, this module is used to output feature summary at
+the end of the configuration.  If any required package is not found,
+processing stops with an error message at the end of the configuration
+phase.
+
+.. code-block:: cmake
+
+  cmake_minimum_required(VERSION 3.15)
+  project(Example)
+
+  add_library(example example.c)
+
+  include(FeatureSummary)
+
+  find_package(CURL)
+  set_package_properties(CURL PROPERTIES TYPE REQUIRED)
+  target_link_libraries(example PRIVATE CURL::libcurl)
+
+  find_package(LibXml2 QUIET)
+  set_package_properties(LibXml2 PROPERTIES TYPE RECOMMENDED)
+  if(LibXml2_FOUND)
+    target_link_libraries(example PRIVATE LibXml2::LibXml2)
+  endif()
+
+  feature_summary(
+    WHAT ALL
+    INCLUDE_QUIET_PACKAGES
+    DESCRIPTION "Feature summary:"
+    FATAL_ON_MISSING_REQUIRED_PACKAGES
+  )
+
+Examples: Setting Feature Info
+""""""""""""""""""""""""""""""
+
+Example for setting the info for a feature:
+
+.. code-block:: cmake
+
+  include(FeatureSummary)
+
+  option(WITH_FOO "Help for foo" ON)
+
+  add_feature_info(Foo WITH_FOO "this feature provides very cool stuff")
+
+Example for setting feature info based on a list of conditions:
+
+.. code-block:: cmake
+
+  include(FeatureSummary)
+
+  option(WITH_FOO "Help for foo" ON)
+  option(WITH_BAR "Help for bar" OFF)
+
+  add_feature_info(
+    FooBar
+    "WITH_FOO;NOT WITH_BAR"
+    "this feature is enabled when WITH_FOO is ON and WITH_BAR turned OFF"
+  )
+
+In the next example feature info are set depending on a full condition
+syntax.  Unlike semicolon-separated list of conditions, this enables using
+entire condition syntax as being the ``if`` clause argument:
+
+.. code-block:: cmake
+
+  include(FeatureSummary)
+
+  option(WITH_FOO "Help for foo" ON)
+  option(WITH_BAR "Help for bar" ON)
+  option(WITH_BAZ "Help for baz" OFF)
+
+  add_feature_info(
+    FooBarBaz
+    "WITH_FOO AND (WITH_BAR OR WITH_BAZ)"
+    "this feature is enabled when the entire condition is true"
+  )
 #]=======================================================================]
 
 get_property(_fsPkgTypeIsSet GLOBAL PROPERTY FeatureSummary_PKG_TYPES SET)
@@ -105,15 +632,7 @@
   set_property(GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE OPTIONAL)
 endif()
 
-#[=======================================================================[.rst:
-
-Functions
-^^^^^^^^^
-
-#]=======================================================================]
-
 function(_FS_GET_FEATURE_SUMMARY _property _var _includeQuiet)
-
   get_property(_fsPkgTypes GLOBAL PROPERTY FeatureSummary_PKG_TYPES)
   get_property(_fsDefaultPkgType GLOBAL PROPERTY FeatureSummary_DEFAULT_PKG_TYPE)
 
@@ -208,155 +727,6 @@
   set(${_var} "${_currentFeatureText}" PARENT_SCOPE)
 endfunction()
 
-
-#[=======================================================================[.rst:
-.. command:: feature_summary
-
-  .. code-block:: cmake
-
-    feature_summary([FILENAME <file>]
-                    [APPEND]
-                    [VAR <variable_name>]
-                    [INCLUDE_QUIET_PACKAGES]
-                    [FATAL_ON_MISSING_REQUIRED_PACKAGES]
-                    [DESCRIPTION <description> | DEFAULT_DESCRIPTION]
-                    [QUIET_ON_EMPTY]
-                    WHAT (ALL
-                         | PACKAGES_FOUND | PACKAGES_NOT_FOUND
-                         | <TYPE>_PACKAGES_FOUND | <TYPE>_PACKAGES_NOT_FOUND
-                         | ENABLED_FEATURES | DISABLED_FEATURES)
-                   )
-
-  This function can be used to print information about
-  enabled or disabled packages and features of a project.  By default,
-  only the names of the features/packages will be printed and their
-  required version when one was specified.  Use
-  :command:`set_package_properties()` to add more useful information, like e.g.
-  a homepage URL for the respective package or their purpose in the project.
-
-  The options are:
-
-  ``WHAT``
-    This is the only mandatory option.  It specifies what information will be
-    printed:
-
-    ``ALL``
-      Print everything.
-    ``ENABLED_FEATURES``
-      The list of all features which are enabled.
-    ``DISABLED_FEATURES``
-      The list of all features which are disabled.
-    ``PACKAGES_FOUND``
-      The list of all packages which have been found.
-    ``PACKAGES_NOT_FOUND``
-      The list of all packages which have not been found.
-
-    For each package type ``<TYPE>`` defined by the
-    :variable:`FeatureSummary_PKG_TYPES` global property, the following
-    information can also be used:
-
-    ``<TYPE>_PACKAGES_FOUND``
-      The list of only packages of type ``<TYPE>`` which have been found.
-    ``<TYPE>_PACKAGES_NOT_FOUND``
-      The list of only packages of type ``<TYPE>`` which have not been found.
-
-    .. versionchanged:: 3.1
-      The ``WHAT`` option is now a multi-value keyword, so that these values can
-      be combined, with the exception of the ``ALL`` value, in order to
-      customize the output.  For example:
-
-    .. code-block:: cmake
-
-      feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES)
-
-  ``FILENAME <file>``
-    If this option is given, the information is printed into this file instead
-    of the terminal.  Relative ``<file>`` path is interpreted as being relative
-    to the current source directory (i.e. :variable:`CMAKE_CURRENT_SOURCE_DIR`).
-
-  ``APPEND``
-    If this option is given, the output is appended to the ``<file>`` provided
-    by the ``FILENAME`` option, otherwise the file is overwritten if it already
-    exists.
-
-  ``VAR <variable_name>``
-    If this option is given, the information is stored into the specified
-    variable ``<variable_name>`` instead of the terminal.
-
-  ``DESCRIPTION <description>``
-    A description or headline which will be printed above the actual content.
-    Without this option, if only one package type was requested, no title is
-    printed, unless a custom string is explicitly set using this option or
-    ``DEFAULT_DESCRIPTION`` option is used that outputs a default title for the
-    requested type.
-
-  ``DEFAULT_DESCRIPTION``
-    .. versionadded:: 3.9
-
-    The default description or headline to be printed above the content as
-    opposed to the customizable ``DESCRIPTION <description>``.
-
-  ``INCLUDE_QUIET_PACKAGES``
-    If this option is given, packages which have been searched with
-    :command:`find_package(... QUIET)` will also be listed.  By default they are
-    skipped.
-
-  ``FATAL_ON_MISSING_REQUIRED_PACKAGES``
-    If this option is given, CMake will abort with fatal error if a package
-    which is marked as one of the package types listed in the
-    :variable:`FeatureSummary_REQUIRED_PKG_TYPES` global property has not been
-    found.
-
-  The :variable:`FeatureSummary_DEFAULT_PKG_TYPE` global property can be
-  modified to change the default package type assigned when not explicitly
-  assigned by the user.
-
-  ``QUIET_ON_EMPTY``
-    .. versionadded:: 3.8
-
-    If this option is given, when only one package type was requested, and no
-    packages belonging to that category were found, then no output (including
-    the ``DESCRIPTION``) is printed nor added to the ``FILENAME``, or the
-    ``VAR`` variable.
-
-  Example 1, append everything to a file:
-
-  .. code-block:: cmake
-
-   include(FeatureSummary)
-   feature_summary(WHAT ALL
-                   FILENAME ${CMAKE_BINARY_DIR}/all.log APPEND)
-
-  Example 2, print the enabled features into the variable
-  ``enabledFeaturesText``, including the ``QUIET`` packages:
-
-  .. code-block:: cmake
-
-    include(FeatureSummary)
-    feature_summary(WHAT ENABLED_FEATURES
-                   INCLUDE_QUIET_PACKAGES
-                   DESCRIPTION "Enabled Features:"
-                   VAR enabledFeaturesText)
-    message(STATUS "${enabledFeaturesText}")
-
-  Example 3, add custom package type and print only the categories that are not
-  empty:
-
-  .. code-block:: cmake
-
-    include(FeatureSummary)
-    set_property(GLOBAL APPEND PROPERTY FeatureSummary_PKG_TYPES BUILD)
-    find_package(FOO)
-    set_package_properties(FOO PROPERTIES TYPE BUILD)
-    feature_summary(WHAT BUILD_PACKAGES_FOUND
-                    DESCRIPTION "Build tools found:"
-                    QUIET_ON_EMPTY)
-    feature_summary(WHAT BUILD_PACKAGES_NOT_FOUND
-                    DESCRIPTION "Build tools not found:"
-                    QUIET_ON_EMPTY)
-
-#]=======================================================================]
-
 function(FEATURE_SUMMARY)
 # cmake_parse_arguments(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...)
   set(options APPEND
@@ -498,93 +868,8 @@
   if(requiredPackagesNotFound  AND  _FS_FATAL_ON_MISSING_REQUIRED_PACKAGES)
     message(FATAL_ERROR "feature_summary() Error: REQUIRED package(s) are missing, aborting CMake run.")
   endif()
-
 endfunction()
 
-#[=======================================================================[.rst:
-.. command:: set_package_properties
-
-  .. code-block:: cmake
-
-    set_package_properties(<name> PROPERTIES
-                           [URL <url>]
-                           [DESCRIPTION <description>]
-                           [TYPE (RUNTIME|OPTIONAL|RECOMMENDED|REQUIRED)]
-                           [PURPOSE <purpose>]
-                          )
-
-  Use this function to configure and provide information about the package named
-  ``<name>``, which can then be displayed using the
-  :command:`feature_summary()` command.  This can be performed either directly
-  within the corresponding :ref:`Find module <Find Modules>` or in the project
-  that uses the module after invoking the :command:`find_package()` call.  The
-  features for which information can be set are determined automatically after
-  the :command:`find_package()` command.
-
-  ``URL <url>``
-    This should be the homepage of the package, or something similar.
-    Ideally this is set already directly in the
-    :ref:`Find module <Find Modules>`.
-
-  ``DESCRIPTION <description>``
-    A short description what that package is, at most one sentence.
-    Ideally this is set already directly in the
-    :ref:`Find module <Find Modules>`.
-
-  ``TYPE <type>``
-    What type of dependency has the using project on that package.
-    Default is ``OPTIONAL``.  In this case it is a package which can be used
-    by the project when available at buildtime, but it also work without.
-    ``RECOMMENDED`` is similar to ``OPTIONAL``, i.e.  the project will build if
-    the package is not present, but the functionality of the resulting
-    binaries will be severely limited.  If a ``REQUIRED`` package is not
-    available at buildtime, the project may not even build.  This can be
-    combined with the
-    :command:`feature_summary(FATAL_ON_MISSING_REQUIRED_PACKAGES)` command
-    option.  Last, a ``RUNTIME`` package is a package which is actually not used
-    at all during the build, but which is required for actually running the
-    resulting binaries.  So if such a package is
-    missing, the project can still be built, but it may not work later on.
-    If ``set_package_properties()`` is called multiple times for the same
-    package with different TYPEs, the ``TYPE`` is only changed to higher
-    TYPEs (``RUNTIME < OPTIONAL < RECOMMENDED < REQUIRED``), lower TYPEs are
-    ignored.  The ``TYPE`` property is project-specific, so it cannot be set
-    by the :ref:`Find module <Find Modules>`, but must be set in the project.
-    The accepted types can be changed by setting the
-    :variable:`FeatureSummary_PKG_TYPES` global property.
-
-  ``PURPOSE <purpose>``
-    This describes which features this package enables in the
-    project, i.e.  it tells the user what functionality they get in the
-    resulting binaries.  If ``set_package_properties()`` is called multiple
-    times for a package, all ``PURPOSE`` properties are appended to a list of
-    purposes of the package in the project.  As the ``TYPE`` property, also
-    the ``PURPOSE`` property is project-specific, so it cannot be set by the
-    :ref:`Find module <Find Modules>`, but must be set in the project.
-
-  Example for setting the info for a package:
-
-  .. code-block:: cmake
-
-    include(FeatureSummary)
-    find_package(LibXml2)
-    set_package_properties(LibXml2 PROPERTIES
-                           DESCRIPTION "XML library"
-                           URL "http://xmlsoft.org")
-    # or
-    set_package_properties(LibXml2 PROPERTIES
-                           TYPE RECOMMENDED
-                           PURPOSE "Enables HTML-import in MyWordProcessor")
-    # or
-    set_package_properties(LibXml2 PROPERTIES
-                           TYPE OPTIONAL
-                           PURPOSE "Enables odt-export in MyWordProcessor")
-
-    find_package(DBUS)
-    set_package_properties(DBUS PROPERTIES
-      TYPE RUNTIME
-      PURPOSE "Necessary to disable the screensaver during a presentation")
-#]=======================================================================]
 function(SET_PACKAGE_PROPERTIES _name _props)
   if(NOT "${_props}" STREQUAL "PROPERTIES")
     message(FATAL_ERROR "PROPERTIES keyword is missing in SET_PACKAGE_PROPERTIES() call.")
@@ -609,7 +894,6 @@
     set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_SPP_DESCRIPTION}" )
   endif()
 
-
   if(_SPP_URL)
     get_property(_info  GLOBAL PROPERTY _CMAKE_${_name}_URL)
     if(_info AND NOT "${_info}" STREQUAL "${_SPP_URL}")
@@ -619,7 +903,6 @@
     set_property(GLOBAL PROPERTY _CMAKE_${_name}_URL "${_SPP_URL}" )
   endif()
 
-
   # handle the PURPOSE: use APPEND, since there can be multiple purposes for one package inside a project
   if(_SPP_PURPOSE)
     set_property(GLOBAL APPEND PROPERTY _CMAKE_${_name}_PURPOSE "${_SPP_PURPOSE}" )
@@ -648,68 +931,8 @@
       set_property(GLOBAL PROPERTY _CMAKE_${_name}_TYPE "${_SPP_TYPE}" )
     endif()
   endif()
-
 endfunction()
 
-#[=======================================================================[.rst:
-.. command:: add_feature_info
-
-  .. code-block:: cmake
-
-    add_feature_info(<name> <enabled> <description>)
-
-  Use this function to add information about a feature identified with a given
-  ``<name>``.  The ``<enabled>`` contains whether this feature is enabled or
-  not.  It can be a variable or a list of conditions.
-  ``<description>`` is a text describing the feature.  The information can
-  be displayed using :command:`feature_summary()` for ``ENABLED_FEATURES`` and
-  ``DISABLED_FEATURES`` respectively.
-
-  .. versionchanged:: 3.8
-    ``<enabled>`` can be a list of conditions.
-
-  .. versionchanged:: 4.0
-    Full :ref:`Condition Syntax` is now supported for ``<enabled>``.
-    See policy :policy:`CMP0183`.
-
-  Example for setting the info for a feature:
-
-  .. code-block:: cmake
-
-    include(FeatureSummary)
-
-    option(WITH_FOO "Help for foo" ON)
-    add_feature_info(Foo WITH_FOO "this feature provides very cool stuff")
-
-  Example for setting feature info based on a list of conditions:
-
-  .. code-block:: cmake
-
-    option(WITH_FOO "Help for foo" ON)
-    option(WITH_BAR "Help for bar" OFF)
-    add_feature_info(
-      FooBar
-      "WITH_FOO;NOT WITH_BAR"
-      "this feature is enabled when WITH_FOO is ON and WITH_BAR turned OFF"
-    )
-
-  Example for setting feature info depending on a full condition syntax:
-
-  Unlike semicolon-separated list of conditions, this enables using entire
-  condition syntax as being the ``if`` clause argument, such as grouping
-  conditions with parens and similar.
-
-  .. code-block:: cmake
-
-    option(WITH_FOO "Help for foo" ON)
-    option(WITH_BAR "Help for bar" ON)
-    option(WITH_BAZ "Help for baz" OFF)
-    add_feature_info(
-      FooBarBaz
-      "WITH_FOO AND (WITH_BAR OR WITH_BAZ)"
-      "this feature is enabled when the entire condition is true"
-    )
-#]=======================================================================]
 function(ADD_FEATURE_INFO _name _depends _desc)
   cmake_policy(GET CMP0183 _CDO_CMP0183
     PARENT_SCOPE # undocumented, do not use outside of CMake
@@ -749,34 +972,8 @@
   unset(_CDO_CMP0183)
 endfunction()
 
-
 # The stuff below is only kept for compatibility
 
-#[=======================================================================[.rst:
-Deprecated Functions
-^^^^^^^^^^^^^^^^^^^^
-
-The following legacy and deprecated functions are provided for backward
-compatibility with previous CMake versions:
-
-.. command:: set_package_info
-
-  .. deprecated:: 3.8
-
-  .. code-block:: cmake
-
-    set_package_info(<name> <description> [ <url> [<purpose>] ])
-
-  Set up information about the package ``<name>``, which can then be displayed
-  via :command:`feature_summary()`.  This can be done either directly in the
-  :ref:`Find module <Find Modules>` or in the project which uses the
-  ``FeatureSummary`` module after the :command:`find_package()` call.  The
-  features for which information can be set are added automatically by the
-  ``find_package()`` command.
-
-  This function is deprecated.  Use the :command:`set_package_properties()`, and
-  :command:`add_feature_info()` functions instead.
-#]=======================================================================]
 function(SET_PACKAGE_INFO _name _desc)
   message(DEPRECATION "SET_PACKAGE_INFO is deprecated. Use SET_PACKAGE_PROPERTIES instead.")
   unset(_url)
@@ -796,62 +993,17 @@
   endif()
 endfunction()
 
-#[=======================================================================[.rst:
-.. command:: set_feature_info
-
-  .. deprecated:: 3.8
-
-  .. code-block:: cmake
-
-    set_feature_info(<name> <description> [<url>])
-
-  Does the same as:
-
-  .. code-block:: cmake
-
-    set_package_info(<name> <description> [<url>])
-#]=======================================================================]
 function(SET_FEATURE_INFO)
   message(DEPRECATION "SET_FEATURE_INFO is deprecated. Use ADD_FEATURE_INFO instead.")
   set_package_info(${ARGN})
 endfunction()
 
-#[=======================================================================[.rst:
-.. command:: print_enabled_features
-
-  .. deprecated:: 3.8
-
-  .. code-block:: cmake
-
-    print_enabled_features()
-
-  Does the same as:
-
-  .. code-block:: cmake
-
-    feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:")
-#]=======================================================================]
 function(PRINT_ENABLED_FEATURES)
   message(DEPRECATION "PRINT_ENABLED_FEATURES is deprecated. Use
     feature_summary(WHAT ENABLED_FEATURES DESCRIPTION \"Enabled features:\")")
   feature_summary(WHAT ENABLED_FEATURES  DESCRIPTION "Enabled features:")
 endfunction()
 
-#[=======================================================================[.rst:
-.. command:: print_disabled_features
-
-  .. deprecated:: 3.8
-
-  .. code-block:: cmake
-
-    print_disabled_features()
-
-  Does the same as:
-
-  .. code-block:: cmake
-
-    feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
-#]=======================================================================]
 function(PRINT_DISABLED_FEATURES)
   message(DEPRECATION "PRINT_DISABLED_FEATURES is deprecated. Use
     feature_summary(WHAT DISABLED_FEATURES DESCRIPTION \"Disabled features:\")")
diff --git a/Modules/FindALSA.cmake b/Modules/FindALSA.cmake
index 1198abe..d7e822b 100644
--- a/Modules/FindALSA.cmake
+++ b/Modules/FindALSA.cmake
@@ -5,7 +5,11 @@
 FindALSA
 --------
 
-Finds the Advanced Linux Sound Architecture (ALSA) library (``asound``).
+Finds the Advanced Linux Sound Architecture (ALSA) library (``asound``):
+
+.. code-block:: cmake
+
+  find_package(ALSA [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -24,7 +28,12 @@
 This module defines the following variables:
 
 ``ALSA_FOUND``
-  Boolean indicating whether the ALSA library is found.
+  Boolean indicating whether (the requested version of) ALSA library is found.
+
+``ALSA_VERSION``
+  .. versionadded:: 4.2
+
+  The version of ALSA found.
 
 ``ALSA_LIBRARIES``
   List of libraries needed for linking to use ALSA library.
@@ -43,6 +52,17 @@
 ``ALSA_LIBRARY``
   The absolute path of the asound library.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``ALSA_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``ALSA_VERSION``.
+
+  The version of ALSA found.
+
 Examples
 ^^^^^^^^
 
@@ -68,14 +88,15 @@
 if(ALSA_INCLUDE_DIR AND EXISTS "${ALSA_INCLUDE_DIR}/alsa/version.h")
   file(STRINGS "${ALSA_INCLUDE_DIR}/alsa/version.h" alsa_version_str REGEX "^#define[\t ]+SND_LIB_VERSION_STR[\t ]+\".*\"")
 
-  string(REGEX REPLACE "^.*SND_LIB_VERSION_STR[\t ]+\"([^\"]*)\".*$" "\\1" ALSA_VERSION_STRING "${alsa_version_str}")
+  string(REGEX REPLACE "^.*SND_LIB_VERSION_STR[\t ]+\"([^\"]*)\".*$" "\\1" ALSA_VERSION "${alsa_version_str}")
+  set(ALSA_VERSION_STRING "${ALSA_VERSION}")
   unset(alsa_version_str)
 endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(ALSA
                                   REQUIRED_VARS ALSA_LIBRARY ALSA_INCLUDE_DIR
-                                  VERSION_VAR ALSA_VERSION_STRING)
+                                  VERSION_VAR ALSA_VERSION)
 
 if(ALSA_FOUND)
   set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
diff --git a/Modules/FindASPELL.cmake b/Modules/FindASPELL.cmake
index 2c5cb93..3d712d6 100644
--- a/Modules/FindASPELL.cmake
+++ b/Modules/FindASPELL.cmake
@@ -5,12 +5,23 @@
 FindASPELL
 ----------
 
-Finds the GNU Aspell spell checker library.
+Finds the GNU Aspell spell checker library:
+
+.. code-block:: cmake
+
+  find_package(ASPELL [<version>] [COMPONENTS <components>] [...])
 
 Components
 ^^^^^^^^^^
 
-This module supports the following components:
+This module supports optional components which can be specified using the
+:command:`find_package` command:
+
+.. code-block:: cmake
+
+  find_package(ASPELL [COMPONENTS <components>...])
+
+Supported components include:
 
 ``ASPELL``
   .. versionadded:: 4.1
@@ -22,13 +33,7 @@
 
   Finds the Aspell command-line interactive spell checker executable.
 
-Components can be specified using the standard CMake syntax:
-
-.. code-block:: cmake
-
-  find_package(ASPELL [COMPONENTS <components>...])
-
-If no ``COMPONENTS`` are specified, the module searches for both the ``ASPELL``
+If no components are specified, the module searches for both the ``ASPELL``
 and ``Executable`` components by default.
 
 Imported Targets
diff --git a/Modules/FindAVIFile.cmake b/Modules/FindAVIFile.cmake
index d3387ea..f5c2786 100644
--- a/Modules/FindAVIFile.cmake
+++ b/Modules/FindAVIFile.cmake
@@ -5,7 +5,11 @@
 FindAVIFile
 -----------
 
-Finds `AVIFile <https://avifile.sourceforge.net/>`_ library and include paths.
+Finds `AVIFile <https://avifile.sourceforge.net/>`_ library and include paths:
+
+.. code-block:: cmake
+
+  find_package(AVIFile [...])
 
 AVIFile is a set of libraries for i386 machines to use various AVI codecs.
 Support is limited beyond Linux.  Windows provides native AVI support, and so
@@ -17,8 +21,8 @@
 This module defines the following variables:
 
 ``AVIFile_FOUND``
-  True if AVIFile is found.  For backward compatibility, the ``AVIFILE_FOUND``
-  variable is also set to the same value.
+  Boolean indicating whether AVIFile is found.  For backward compatibility,
+  the ``AVIFILE_FOUND`` variable is also set to the same value.
 ``AVIFILE_LIBRARIES``
   The libraries to link against.
 ``AVIFILE_DEFINITIONS``
@@ -27,7 +31,7 @@
 Cache Variables
 ^^^^^^^^^^^^^^^
 
-The following cache variables may be also set:
+The following cache variables may also be set:
 
 ``AVIFILE_INCLUDE_DIR``
   Directory containing ``avifile.h`` and other AVIFile headers.
@@ -35,11 +39,26 @@
 Examples
 ^^^^^^^^
 
-Finding AVIFile:
+Finding AVIFile and conditionally creating an interface :ref:`Imported Target
+<Imported Targets>` that encapsulates its usage requirements for linking to a
+project target:
 
 .. code-block:: cmake
 
   find_package(AVIFile)
+
+  if(AVIFile_FOUND AND NOT TARGET AVIFile::AVIFile)
+    add_library(AVIFile::AVIFile INTERFACE IMPORTED)
+    set_target_properties(
+      AVIFile::AVIFile
+      PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${AVIFILE_INCLUDE_DIR}"
+        INTERFACE_LINK_LIBRARIES "${AVIFILE_LIBRARIES}"
+        INTERFACE_COMPILE_DEFINITIONS "${AVIFILE_DEFINITIONS}"
+    )
+  endif()
+
+  target_link_libraries(example PRIVATE AVIFile::AVIFile)
 #]=======================================================================]
 
 if (UNIX)
@@ -50,7 +69,10 @@
 endif ()
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(AVIFile DEFAULT_MSG AVIFILE_INCLUDE_DIR AVIFILE_AVIPLAY_LIBRARY)
+find_package_handle_standard_args(
+  AVIFile
+  REQUIRED_VARS AVIFILE_AVIPLAY_LIBRARY AVIFILE_INCLUDE_DIR
+)
 
 if (AVIFile_FOUND)
     set(AVIFILE_LIBRARIES ${AVIFILE_AVIPLAY_LIBRARY})
diff --git a/Modules/FindArmadillo.cmake b/Modules/FindArmadillo.cmake
index f185f10..96fb139 100644
--- a/Modules/FindArmadillo.cmake
+++ b/Modules/FindArmadillo.cmake
@@ -5,8 +5,13 @@
 FindArmadillo
 -------------
 
-Finds the Armadillo C++ library.  Armadillo is a library for linear algebra and
-scientific computing.
+Finds the Armadillo C++ library:
+
+.. code-block:: cmake
+
+  find_package(Armadillo [<version>] [...])
+
+Armadillo is a library for linear algebra and scientific computing.
 
 .. versionadded:: 3.18
   Support for linking wrapped libraries directly (see the
@@ -16,30 +21,68 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``Armadillo_FOUND``
-  Set to true if the library is found.  For backward compatibility, the
-  ``ARMADILLO_FOUND`` variable is also set to the same value.
+  Boolean indicating whether the (requested version of) Armadillo library is
+  found.  For backward compatibility, the ``ARMADILLO_FOUND`` variable is
+  also set to the same value.
+
+``Armadillo_VERSION``
+  .. versionadded:: 4.2
+
+  The version of Armadillo found (e.g., ``14.90.0``).
+
+``Armadillo_VERSION_NAME``
+  .. versionadded:: 4.2
+
+  The version name of Armadillo found (e.g., ``Antipodean Antileech``).
+
 ``ARMADILLO_INCLUDE_DIRS``
   List of required include directories.
+
 ``ARMADILLO_LIBRARIES``
   List of libraries to be linked.
+
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
 ``ARMADILLO_VERSION_STRING``
-  Version as a string (ex: ``1.0.4``).
+  .. deprecated:: 4.2
+    Superseded by the ``Armadillo_VERSION``.
+
+  The version of Armadillo found.
+
 ``ARMADILLO_VERSION_MAJOR``
+  .. deprecated:: 4.2
+    Superseded by the ``Armadillo_VERSION``.
+
   Major version number.
+
 ``ARMADILLO_VERSION_MINOR``
+  .. deprecated:: 4.2
+    Superseded by the ``Armadillo_VERSION``.
+
   Minor version number.
+
 ``ARMADILLO_VERSION_PATCH``
+  .. deprecated:: 4.2
+    Superseded by the ``Armadillo_VERSION``.
+
   Patch version number.
+
 ``ARMADILLO_VERSION_NAME``
-  Name of the version (ex: ``Antipodean Antileech``).
+  .. deprecated:: 4.2
+    Superseded by the ``Armadillo_VERSION_NAME``.
+
+  The version name of Armadillo found (e.g., ``Antipodean Antileech``).
 
 Examples
 ^^^^^^^^
 
-Using Armadillo:
+Finding Armadillo and creating an imported target:
 
 .. code-block:: cmake
 
@@ -79,10 +122,9 @@
   set(ARMADILLO_VERSION_MAJOR 0)
   set(ARMADILLO_VERSION_MINOR 0)
   set(ARMADILLO_VERSION_PATCH 0)
-  set(ARMADILLO_VERSION_NAME "EARLY RELEASE")
+  set(Armadillo_VERSION_NAME "EARLY RELEASE")
 
   if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp")
-
     # Read and parse armdillo version header file for version number
     file(STRINGS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/arma_version.hpp" _ARMA_HEADER_CONTENTS REGEX "#define ARMA_VERSION_[A-Z]+ ")
     string(REGEX REPLACE ".*#define ARMA_VERSION_MAJOR ([0-9]+).*" "\\1" ARMADILLO_VERSION_MAJOR "${_ARMA_HEADER_CONTENTS}")
@@ -90,11 +132,13 @@
     string(REGEX REPLACE ".*#define ARMA_VERSION_PATCH ([0-9]+).*" "\\1" ARMADILLO_VERSION_PATCH "${_ARMA_HEADER_CONTENTS}")
 
     # WARNING: The number of spaces before the version name is not one.
-    string(REGEX REPLACE ".*#define ARMA_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" ARMADILLO_VERSION_NAME "${_ARMA_HEADER_CONTENTS}")
+    string(REGEX REPLACE ".*#define ARMA_VERSION_NAME\ +\"([0-9a-zA-Z\ _-]+)\".*" "\\1" Armadillo_VERSION_NAME "${_ARMA_HEADER_CONTENTS}")
 
+    set(ARMADILLO_VERSION_NAME "${Armadillo_VERSION_NAME}")
   endif()
 
-  set(ARMADILLO_VERSION_STRING "${ARMADILLO_VERSION_MAJOR}.${ARMADILLO_VERSION_MINOR}.${ARMADILLO_VERSION_PATCH}")
+  set(Armadillo_VERSION "${ARMADILLO_VERSION_MAJOR}.${ARMADILLO_VERSION_MINOR}.${ARMADILLO_VERSION_PATCH}")
+  set(ARMADILLO_VERSION_STRING "${Armadillo_VERSION}")
 endif ()
 
 if(EXISTS "${ARMADILLO_INCLUDE_DIR}/armadillo_bits/config.hpp")
@@ -150,7 +194,7 @@
 
 find_package_handle_standard_args(Armadillo
   REQUIRED_VARS ARMADILLO_INCLUDE_DIR ${_ARMA_REQUIRED_VARS}
-  VERSION_VAR ARMADILLO_VERSION_STRING)
+  VERSION_VAR Armadillo_VERSION)
 
 if (Armadillo_FOUND)
   set(ARMADILLO_INCLUDE_DIRS ${ARMADILLO_INCLUDE_DIR})
diff --git a/Modules/FindBISON.cmake b/Modules/FindBISON.cmake
index ef76f6a..6acebc8 100644
--- a/Modules/FindBISON.cmake
+++ b/Modules/FindBISON.cmake
@@ -10,7 +10,7 @@
 
 .. code-block:: cmake
 
-  find_package(BISON [<version>] ...)
+  find_package(BISON [<version>] [...])
 
 Bison is a parser generator that replaced earlier Yacc (Yet Another
 Compiler-Compiler).  On Unix-like systems, most common implementation is
diff --git a/Modules/FindBLAS.cmake b/Modules/FindBLAS.cmake
index b45a279..551864e 100644
--- a/Modules/FindBLAS.cmake
+++ b/Modules/FindBLAS.cmake
@@ -5,34 +5,67 @@
 FindBLAS
 --------
 
-Find Basic Linear Algebra Subprograms (BLAS) library
+Finds the installed Basic Linear Algebra Subprograms (BLAS) Fortran library,
+which implements the `BLAS linear-algebra interface`_:
 
-This module finds an installed Fortran library that implements the
-`BLAS linear-algebra interface`_.
+.. code-block:: cmake
+
+  find_package(BLAS [...])
 
 At least one of the ``C``, ``CXX``, or ``Fortran`` languages must be enabled.
 
 .. _`BLAS linear-algebra interface`: https://netlib.org/blas/
 
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module provides the following :ref:`Imported Targets`:
+
+``BLAS::BLAS``
+  .. versionadded:: 3.18
+
+  Target encapsulating the libraries and usage requirements to use BLAS,
+  available only if BLAS is found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``BLAS_FOUND``
+  Boolean indicating whether the library implementing the BLAS interface is
+  found.
+``BLAS_LINKER_FLAGS``
+  Uncached list of required linker flags (excluding ``-l`` and ``-L``).
+``BLAS_LIBRARIES``
+  Uncached list of libraries (using full path name) to link against
+  to use BLAS (may be empty if compiler implicitly links BLAS).
+``BLAS95_LIBRARIES``
+  Uncached list of libraries (using full path name) to link against
+  to use BLAS95 interface.
+``BLAS95_FOUND``
+  Boolean indicating whether the library implementing the BLAS95 interface
+  is found.
+
 Input Variables
 ^^^^^^^^^^^^^^^
 
 The following variables may be set to influence this module's behavior:
 
 ``BLA_STATIC``
-  if ``ON`` use static linkage
+  If ``ON``, the static linkage will be used.
 
 ``BLA_VENDOR``
   Set to one of the :ref:`BLAS/LAPACK Vendors` to search for BLAS only
   from the specified vendor.  If not set, all vendors are considered.
 
 ``BLA_F95``
-  if ``ON`` tries to find the BLAS95 interfaces
+  If ``ON``, the module tries to find the BLAS95 interfaces.
 
 ``BLA_PREFER_PKGCONFIG``
   .. versionadded:: 3.11
 
-  if set ``pkg-config`` will be used to search for a BLAS library first
+  If set, ``pkg-config`` will be used to search for a BLAS library first
   and if one is found that is preferred
 
 ``BLA_PKGCONFIG_BLAS``
@@ -69,41 +102,13 @@
 
   This is currently only supported by NVIDIA NVPL.
 
-Imported Targets
-^^^^^^^^^^^^^^^^
-
-This module defines the following :prop_tgt:`IMPORTED` targets:
-
-``BLAS::BLAS``
-  .. versionadded:: 3.18
-
-  The libraries to use for BLAS, if found.
-
-Result Variables
-^^^^^^^^^^^^^^^^
-
-This module defines the following variables:
-
-``BLAS_FOUND``
-  library implementing the BLAS interface is found
-``BLAS_LINKER_FLAGS``
-  uncached list of required linker flags (excluding ``-l`` and ``-L``).
-``BLAS_LIBRARIES``
-  uncached list of libraries (using full path name) to link against
-  to use BLAS (may be empty if compiler implicitly links BLAS)
-``BLAS95_LIBRARIES``
-  uncached list of libraries (using full path name) to link against
-  to use BLAS95 interface
-``BLAS95_FOUND``
-  library implementing the BLAS95 interface is found
-
 .. _`BLAS/LAPACK Vendors`:
 
 BLAS/LAPACK Vendors
 ^^^^^^^^^^^^^^^^^^^
 
 ``Generic``
-  Generic reference implementation
+  Generic reference implementation.
 
 ``ACML``, ``ACML_MP``, ``ACML_GPU``
   AMD Core Math Library
@@ -111,31 +116,31 @@
 ``AOCL``, ``AOCL_mt``
   .. versionadded:: 3.27
 
-  AMD Optimizing CPU Libraries
+  AMD Optimizing CPU Libraries.
 
 ``Apple``, ``NAS``
-  Apple BLAS (Accelerate), and Apple NAS (vecLib)
+  Apple BLAS (Accelerate), and Apple NAS (vecLib).
 
 ``Arm``, ``Arm_mp``, ``Arm_ilp64``, ``Arm_ilp64_mp``
   .. versionadded:: 3.18
 
-  Arm Performance Libraries
+  Arm Performance Libraries.
 
 ``ATLAS``
-  Automatically Tuned Linear Algebra Software
+  Automatically Tuned Linear Algebra Software.
 
 ``CXML``, ``DXML``
-  Compaq/Digital Extended Math Library
+  Compaq/Digital Extended Math Library.
 
 ``EML``, ``EML_mt``
   .. versionadded:: 3.20
 
-  Elbrus Math Library
+  Elbrus Math Library.
 
 ``FLAME``
   .. versionadded:: 3.11
 
-  BLIS Framework
+  BLIS Framework.
 
 ``FlexiBLAS``
   .. versionadded:: 3.19
@@ -143,71 +148,71 @@
 ``Fujitsu_SSL2``, ``Fujitsu_SSL2BLAMP``, ``Fujitsu_SSL2SVE``, ``Fujitsu_SSL2BLAMPSVE``
   .. versionadded:: 3.20
 
-  Fujitsu SSL2 serial and parallel blas/lapack with SVE instructions
+  Fujitsu SSL2 serial and parallel blas/lapack with SVE instructions.
 
 ``Goto``
-  GotoBLAS
+  GotoBLAS.
 
 ``IBMESSL``, ``IBMESSL_SMP``
 
-  IBM Engineering and Scientific Subroutine Library
+  IBM Engineering and Scientific Subroutine Library.
 
 ``Intel``
-  Intel MKL 32 bit and 64 bit obsolete versions
+  Intel MKL 32 bit and 64 bit obsolete versions.
 
 ``Intel10_32``
-  Intel MKL v10 32 bit, threaded code
+  Intel MKL v10 32 bit, threaded code.
 
 ``Intel10_64lp``
-  Intel MKL v10+ 64 bit, threaded code, lp64 model
+  Intel MKL v10+ 64 bit, threaded code, lp64 model.
 
 ``Intel10_64lp_seq``
-  Intel MKL v10+ 64 bit, sequential code, lp64 model
+  Intel MKL v10+ 64 bit, sequential code, lp64 model.
 
 ``Intel10_64ilp``
   .. versionadded:: 3.13
 
-  Intel MKL v10+ 64 bit, threaded code, ilp64 model
+  Intel MKL v10+ 64 bit, threaded code, ilp64 model.
 
 ``Intel10_64ilp_seq``
   .. versionadded:: 3.13
 
-  Intel MKL v10+ 64 bit, sequential code, ilp64 model
+  Intel MKL v10+ 64 bit, sequential code, ilp64 model.
 
 ``Intel10_64_dyn``
   .. versionadded:: 3.17
 
-  Intel MKL v10+ 64 bit, single dynamic library
+  Intel MKL v10+ 64 bit, single dynamic library.
 
 ``libblastrampoline``
   .. versionadded:: 3.30
 
-  A BLAS/LAPACK demuxing library using PLT trampolines
+  A BLAS/LAPACK demuxing library using PLT trampolines.
 
 ``NVPL``
   .. versionadded:: 4.1
 
-  NVIDIA Performance Libraries
+  NVIDIA Performance Libraries.
 
 ``NVHPC``
   .. versionadded:: 3.21
 
-  NVIDIA HPC SDK
+  NVIDIA HPC SDK.
 
 ``OpenBLAS``
   .. versionadded:: 3.6
 
 ``PhiPACK``
-  Portable High Performance ANSI C (PHiPAC)
+  Portable High Performance ANSI C (PHiPAC).
 
 ``SCSL``, ``SCSL_mp``
-  Scientific Computing Software Library
+  Scientific Computing Software Library.
 
 ``SGIMATH``
-  SGI Scientific Mathematical Library
+  SGI Scientific Mathematical Library.
 
 ``SunPerf``
-  Sun Performance Library
+  Sun Performance Library.
 
 .. _`Intel MKL`:
 
@@ -270,6 +275,15 @@
 
     . /opt/intel/oneapi/compiler/latest/env/vars.sh
 
+Examples
+^^^^^^^^
+
+Finding BLAS and linking it to a project target:
+
+.. code-block:: cmake
+
+  find_package(BLAS)
+  target_link_libraries(example PRIVATE BLAS::BLAS)
 #]=======================================================================]
 
 # The approach follows that of the ``autoconf`` macro file, ``acx_blas.m4``
diff --git a/Modules/FindBZip2.cmake b/Modules/FindBZip2.cmake
index 0b9f3fe..6432ec5 100644
--- a/Modules/FindBZip2.cmake
+++ b/Modules/FindBZip2.cmake
@@ -28,8 +28,14 @@
 This module defines the following variables:
 
 ``BZip2_FOUND``
-  Boolean indicating whether the BZip2 library is found.  For backward
-  compatibility, the ``BZIP2_FOUND`` variable is also set to the same value.
+  Boolean indicating whether (the requested version of) BZip2 library is
+  found.  For backward compatibility, the ``BZIP2_FOUND`` variable is also
+  set to the same value.
+
+``BZip2_VERSION``
+  .. versionadded:: 4.2
+
+  The version of BZip2 found.
 
 ``BZIP2_INCLUDE_DIRS``
   .. versionadded:: 3.12
@@ -39,11 +45,6 @@
 ``BZIP2_LIBRARIES``
   Libraries needed for linking to use BZip2.
 
-``BZIP2_VERSION``
-  .. versionadded:: 3.26
-
-  The version of BZip2 found.
-
 Cache Variables
 ^^^^^^^^^^^^^^^
 
@@ -63,14 +64,22 @@
   (e.g., ``BZ2_bzCompressInit()``).  Versions of BZip2 prior to 1.0.0 used
   unprefixed function names (e.g., ``bzCompressInit()``).
 
-Legacy Variables
-^^^^^^^^^^^^^^^^
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
 
 The following variables are provided for backward compatibility:
 
 ``BZIP2_VERSION_STRING``
-  .. versionchanged:: 3.26
-    Superseded by ``BZIP2_VERSION``.
+  .. deprecated:: 3.26
+    Superseded by the ``BZIP2_VERSION`` (and ``BZip2_VERSION``).
+
+  The version of BZip2 found.
+
+``BZIP2_VERSION``
+  .. versionadded:: 3.26
+
+  .. deprecated:: 4.2
+    Superseded by the ``BZip2_VERSION``.
 
   The version of BZip2 found.
 
@@ -108,12 +117,13 @@
     file(STRINGS "${BZIP2_INCLUDE_DIR}/bzlib.h" BZLIB_H REGEX "bzip2/libbzip2 version [0-9]+\\.[^ ]+ of [0-9]+ ")
     string(REGEX REPLACE ".* bzip2/libbzip2 version ([0-9]+\\.[^ ]+) of [0-9]+ .*" "\\1" BZIP2_VERSION_STRING "${BZLIB_H}")
     set(BZIP2_VERSION ${BZIP2_VERSION_STRING})
+    set(BZip2_VERSION ${BZIP2_VERSION_STRING})
 endif ()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(BZip2
                                   REQUIRED_VARS BZIP2_LIBRARIES BZIP2_INCLUDE_DIR
-                                  VERSION_VAR BZIP2_VERSION)
+                                  VERSION_VAR BZip2_VERSION)
 
 if (BZip2_FOUND)
   set(BZIP2_INCLUDE_DIRS ${BZIP2_INCLUDE_DIR})
@@ -126,7 +136,7 @@
 
   # Versions before 1.0.2 required <stdio.h> for the FILE definition.
   set(BZip2_headers "bzlib.h")
-  if(BZIP2_VERSION VERSION_LESS "1.0.2")
+  if(BZip2_VERSION VERSION_LESS "1.0.2")
     list(PREPEND BZip2_headers "stdio.h")
   endif()
   check_symbol_exists(BZ2_bzCompressInit "${BZip2_headers}" BZIP2_NEED_PREFIX)
diff --git a/Modules/FindBacktrace.cmake b/Modules/FindBacktrace.cmake
index 0674c5f..052e6b5 100644
--- a/Modules/FindBacktrace.cmake
+++ b/Modules/FindBacktrace.cmake
@@ -6,7 +6,11 @@
 -------------
 
 Finds `backtrace(3) <https://man7.org/linux/man-pages/man3/backtrace.3.html>`_,
-a library that provides functions for application self-debugging.
+a library that provides functions for application self-debugging:
+
+.. code-block:: cmake
+
+  find_package(Backtrace [...])
 
 This module checks whether ``backtrace(3)`` is supported, either through the
 standard C library (``libc``), or a separate library.
@@ -14,11 +18,11 @@
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.30
-
 This module provides the following :ref:`Imported Targets`:
 
 ``Backtrace::Backtrace``
+  .. versionadded:: 3.30
+
   An interface library encapsulating the usage requirements of Backtrace.  This
   target is available only when Backtrace is found.
 
@@ -27,13 +31,15 @@
 
 This module defines the following variables:
 
-``Backtrace_INCLUDE_DIRS``
-  The include directories needed to use ``backtrace(3)`` header.
-``Backtrace_LIBRARIES``
-  The libraries (linker flags) needed to use ``backtrace(3)``, if any.
 ``Backtrace_FOUND``
   Boolean indicating whether the ``backtrace(3)`` support is available.
 
+``Backtrace_INCLUDE_DIRS``
+  The include directories needed to use ``backtrace(3)`` header.
+
+``Backtrace_LIBRARIES``
+  The libraries (linker flags) needed to use ``backtrace(3)``, if any.
+
 Cache Variables
 ^^^^^^^^^^^^^^^
 
@@ -43,18 +49,20 @@
   The header file needed for ``backtrace(3)``.  This variable allows dynamic
   usage of the header in the project code.  It can also be overridden by the
   user.
-``Backtrace_LIBRARY``
-  The external library providing backtrace, if any.
+
 ``Backtrace_INCLUDE_DIR``
   The directory holding the ``backtrace(3)`` header.
 
+``Backtrace_LIBRARY``
+  The external library providing backtrace, if any.
+
 Examples
 ^^^^^^^^
 
 Finding Backtrace and linking it to a project target as of CMake 3.30:
 
 .. code-block:: cmake
-  :caption: CMakeLists.txt
+  :caption: ``CMakeLists.txt``
 
   find_package(Backtrace)
   target_link_libraries(app PRIVATE Backtrace::Backtrace)
@@ -63,7 +71,7 @@
 header file created by :command:`configure_file`:
 
 .. code-block:: cmake
-  :caption: CMakeLists.txt
+  :caption: ``CMakeLists.txt``
 
   add_library(app app.c)
 
@@ -73,7 +81,7 @@
   configure_file(config.h.in config.h)
 
 .. code-block:: c
-  :caption: config.h.in
+  :caption: ``config.h.in``
 
   #cmakedefine01 Backtrace_FOUND
   #if Backtrace_FOUND
@@ -81,7 +89,7 @@
   #endif
 
 .. code-block:: c
-  :caption: app.c
+  :caption: ``app.c``
 
   #include "config.h"
 
@@ -89,7 +97,7 @@
 be defined manually:
 
 .. code-block:: cmake
-  :caption: CMakeLists.txt
+  :caption: ``CMakeLists.txt``
 
   find_package(Backtrace)
   if(Backtrace_FOUND AND NOT TARGET Backtrace::Backtrace)
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 8ae4223..78df671 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -47,7 +47,7 @@
 This module defines the following variables:
 
 ``Boost_FOUND``
-  True if headers and requested libraries were found.
+  Boolean indicating whether headers and requested libraries were found.
 
 ``Boost_INCLUDE_DIRS``
   Boost include directories.
@@ -59,7 +59,8 @@
   Boost component libraries to be linked.
 
 ``Boost_<COMPONENT>_FOUND``
-  True if component ``<COMPONENT>`` was found (``<COMPONENT>`` name is upper-case).
+  Boolean indicating whether the component ``<COMPONENT>`` was found
+  (``<COMPONENT>`` name is upper-case).
 
 ``Boost_<COMPONENT>_LIBRARY``
   Libraries to link for component ``<COMPONENT>`` (may include
@@ -102,7 +103,7 @@
 .. versionadded:: 3.15
   The ``Boost_VERSION_<PART>`` variables.
 
-Cache variables
+Cache Variables
 ^^^^^^^^^^^^^^^
 
 Search results are saved persistently in CMake cache entries:
@@ -172,7 +173,7 @@
 
 .. versionadded:: 3.5
 
-This module defines the following :prop_tgt:`IMPORTED` targets:
+This module provides the following :ref:`Imported Targets`:
 
 ``Boost::boost``
   Target for header-only dependencies. (Boost include directory).
diff --git a/Modules/FindBullet.cmake b/Modules/FindBullet.cmake
index 61a5fb3..7ae571f 100644
--- a/Modules/FindBullet.cmake
+++ b/Modules/FindBullet.cmake
@@ -5,7 +5,11 @@
 FindBullet
 ----------
 
-Finds the Bullet physics engine.
+Finds the Bullet physics engine:
+
+.. code-block:: cmake
+
+  find_package(Bullet [...])
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -13,8 +17,8 @@
 This module defines the following variables:
 
 ``Bullet_FOUND``
-  Boolean true if Bullet was found.  For backward compatibility, the
-  ``BULLET_FOUND`` variable is also set to the same value.
+  Boolean indicating whether Bullet was found.  For backward compatibility,
+  the ``BULLET_FOUND`` variable is also set to the same value.
 ``BULLET_INCLUDE_DIRS``
   The Bullet include directories.
 ``BULLET_LIBRARIES``
@@ -33,11 +37,25 @@
 Examples
 ^^^^^^^^
 
-Finding Bullet:
+Finding Bullet and conditionally creating an interface :ref:`imported target
+<Imported Targets>` that encapsulates its usage requirements for linking to a
+project target:
 
 .. code-block:: cmake
 
   find_package(Bullet)
+
+  if(Bullet_FOUND AND NOT TARGET Bullet::Bullet)
+    add_library(Bullet::Bullet INTERFACE IMPORTED)
+    set_target_properties(
+      Bullet::Bullet
+      PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${BULLET_INCLUDE_DIRS}"
+        INTERFACE_LINK_LIBRARIES "${BULLET_LIBRARIES}"
+    )
+  endif()
+
+  target_link_libraries(example PRIVATE Bullet::Bullet)
 #]=======================================================================]
 
 macro(_FIND_BULLET_LIBRARY _var)
diff --git a/Modules/FindCABLE.cmake b/Modules/FindCABLE.cmake
index af0e6b6..aa68ff4 100644
--- a/Modules/FindCABLE.cmake
+++ b/Modules/FindCABLE.cmake
@@ -8,7 +8,11 @@
 .. versionchanged:: 4.1
   This module is available only if policy :policy:`CMP0191` is not set to ``NEW``.
 
-Finds the CABLE installation and determines its include paths and libraries.
+Finds the CABLE installation and determines its include paths and libraries:
+
+.. code-block:: cmake
+
+  find_package(CABLE [...])
 
 Package called CABLE (CABLE Automates Bindings for Language Extension) was
 initially developed by Kitware to generate bindings to C++ classes for use in
@@ -25,7 +29,7 @@
 Cache Variables
 ^^^^^^^^^^^^^^^
 
-The following cache variables may be set when using this module:
+The following cache variables may also be set:
 
 ``CABLE``
   Path to the ``cable`` executable.
diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake
index b00cd26..f560c51 100644
--- a/Modules/FindCUDAToolkit.cmake
+++ b/Modules/FindCUDAToolkit.cmake
@@ -107,7 +107,7 @@
 
 An :ref:`imported target <Imported targets>` named ``CUDA::toolkit`` is provided.
 
-This module defines :prop_tgt:`IMPORTED` targets for each
+This module provides :ref:`Imported Targets` for each
 of the following libraries that are part of the CUDAToolkit:
 
 - `CUDA Runtime Library`_
@@ -568,8 +568,6 @@
     found to determine the CUDA Toolkit version as well as determining other
     features of the Toolkit.  This variable is set for the convenience of
     modules that depend on this one.
-
-
 #]=======================================================================]
 
 # NOTE: much of this was simply extracted from FindCUDA.cmake.
diff --git a/Modules/FindCURL.cmake b/Modules/FindCURL.cmake
index 1488412..be3c5bb 100644
--- a/Modules/FindCURL.cmake
+++ b/Modules/FindCURL.cmake
@@ -6,7 +6,11 @@
 --------
 
 Finds the native curl installation (include directories and libraries) for
-transferring data with URLS.
+transferring data with URLS:
+
+.. code-block:: cmake
+
+  find_package(CURL [<version>] [COMPONENTS <components>...] [...])
 
 .. versionadded:: 3.17
   If curl is built using its CMake-based build system, it will provide its own
diff --git a/Modules/FindCVS.cmake b/Modules/FindCVS.cmake
index d50a758..de64370 100644
--- a/Modules/FindCVS.cmake
+++ b/Modules/FindCVS.cmake
@@ -5,7 +5,11 @@
 FindCVS
 -------
 
-Finds the Concurrent Versions System (CVS).
+Finds the Concurrent Versions System (CVS):
+
+.. code-block:: cmake
+
+  find_package(CVS [...])
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -13,7 +17,7 @@
 This module defines the following variables:
 
 ``CVS_FOUND``
-  True if the command-line client was found.
+  Boolean indicating whether the command-line client was found.
 
 Cache Variables
 ^^^^^^^^^^^^^^^
@@ -78,8 +82,5 @@
   )
 mark_as_advanced(CVS_EXECUTABLE)
 
-# Handle the QUIETLY and REQUIRED arguments and set CVS_FOUND to TRUE if
-# all listed variables are TRUE
-
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(CVS DEFAULT_MSG CVS_EXECUTABLE)
diff --git a/Modules/FindCoin3D.cmake b/Modules/FindCoin3D.cmake
index 1d89c60..8fd939b 100644
--- a/Modules/FindCoin3D.cmake
+++ b/Modules/FindCoin3D.cmake
@@ -5,7 +5,11 @@
 FindCoin3D
 ----------
 
-Finds Coin3D (Open Inventor).
+Finds Coin3D (Open Inventor):
+
+.. code-block:: cmake
+
+  find_package(Coin3D [...])
 
 Coin3D is an implementation of the Open Inventor API.  It provides
 data structures and algorithms for 3D visualization.
@@ -16,8 +20,8 @@
 This module defines the following variables:
 
 ``Coin3D_FOUND``
-  True if Coin3D, Open Inventor was found.  For backward compatibility, the
-  ``COIN3D_FOUND`` variable is also set to the same value.
+  Boolean indicating whether Coin3D, Open Inventor is found.  For backward
+  compatibility, the ``COIN3D_FOUND`` variable is also set to the same value.
 
 Cache Variables
 ^^^^^^^^^^^^^^^
@@ -32,11 +36,25 @@
 Examples
 ^^^^^^^^
 
-Finding Coin3D:
+Finding Coin3D and conditionally creating an interface :ref:`imported target
+<Imported Targets>` that encapsulates its usage requirements for linking to a
+project target:
 
 .. code-block:: cmake
 
   find_package(Coin3D)
+
+  if(Coin3D_FOUND AND NOT TARGET Coin3D::Coin3D)
+    add_library(Coin3D::Coin3D INTERFACE IMPORTED)
+    set_target_properties(
+      Coin3D::Coin3D
+      PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${COIN3D_INCLUDE_DIRS}"
+        INTERFACE_LINK_LIBRARIES "${COIN3D_LIBRARIES}"
+    )
+  endif()
+
+  target_link_libraries(example PRIVATE Coin3D::Coin3D)
 #]=======================================================================]
 
 if (WIN32)
diff --git a/Modules/FindCups.cmake b/Modules/FindCups.cmake
index 871a809..2e2e199 100644
--- a/Modules/FindCups.cmake
+++ b/Modules/FindCups.cmake
@@ -5,7 +5,11 @@
 FindCups
 --------
 
-Finds the Common UNIX Printing System (CUPS).
+Finds the Common UNIX Printing System (CUPS):
+
+.. code-block:: cmake
+
+  find_package(Cups [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -24,12 +28,17 @@
 This module defines the following variables:
 
 ``Cups_FOUND``
-  Boolean indicating whether the CUPS is found.  For backward compatibility, the
-  ``CUPS_FOUND`` variable is also set to the same value.
+  Boolean indicating whether (the requested version of) CUPS is found.  For
+  backward compatibility, the ``CUPS_FOUND`` variable is also set to the
+  same value.
+
+``Cups_VERSION``
+  .. versionadded:: 4.2
+
+  The version of CUPS found.
+
 ``CUPS_INCLUDE_DIRS``
   Include directories needed for using CUPS.
-``CUPS_VERSION_STRING``
-  The version of CUPS found.
 
 Cache Variables
 ^^^^^^^^^^^^^^^
@@ -38,6 +47,7 @@
 
 ``CUPS_INCLUDE_DIR``
   The directory containing the CUPS headers.
+
 ``CUPS_LIBRARIES``
   Libraries needed to link against to use CUPS.
 
@@ -50,6 +60,17 @@
   Set this variable to ``TRUE`` to require CUPS version which features the
   ``ippDeleteAttribute()`` function (i.e. at least of CUPS ``1.1.19``).
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``CUPS_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``Cups_VERSION``.
+
+  The version of CUPS found.
+
 Examples
 ^^^^^^^^
 
@@ -83,19 +104,20 @@
     file(STRINGS "${CUPS_INCLUDE_DIR}/cups/cups.h" cups_version_str
          REGEX "^#[\t ]*define[\t ]+CUPS_VERSION_(MAJOR|MINOR|PATCH)[\t ]+[0-9]+$")
 
-    unset(CUPS_VERSION_STRING)
+    unset(Cups_VERSION)
     foreach(VPART MAJOR MINOR PATCH)
         foreach(VLINE ${cups_version_str})
             if(VLINE MATCHES "^#[\t ]*define[\t ]+CUPS_VERSION_${VPART}[\t ]+([0-9]+)$")
                 set(CUPS_VERSION_PART "${CMAKE_MATCH_1}")
-                if(CUPS_VERSION_STRING)
-                    string(APPEND CUPS_VERSION_STRING ".${CUPS_VERSION_PART}")
+                if(Cups_VERSION)
+                    string(APPEND Cups_VERSION ".${CUPS_VERSION_PART}")
                 else()
-                    set(CUPS_VERSION_STRING "${CUPS_VERSION_PART}")
+                    set(Cups_VERSION "${CUPS_VERSION_PART}")
                 endif()
             endif()
         endforeach()
     endforeach()
+    set(CUPS_VERSION_STRING ${Cups_VERSION})
 endif ()
 
 include(FindPackageHandleStandardArgs)
@@ -103,11 +125,11 @@
 if (CUPS_REQUIRE_IPP_DELETE_ATTRIBUTE)
     find_package_handle_standard_args(Cups
                                       REQUIRED_VARS CUPS_LIBRARIES CUPS_INCLUDE_DIR CUPS_HAS_IPP_DELETE_ATTRIBUTE
-                                      VERSION_VAR CUPS_VERSION_STRING)
+                                      VERSION_VAR Cups_VERSION)
 else ()
     find_package_handle_standard_args(Cups
                                       REQUIRED_VARS CUPS_LIBRARIES CUPS_INCLUDE_DIR
-                                      VERSION_VAR CUPS_VERSION_STRING)
+                                      VERSION_VAR Cups_VERSION)
 endif ()
 
 mark_as_advanced(CUPS_INCLUDE_DIR CUPS_LIBRARIES)
diff --git a/Modules/FindCurses.cmake b/Modules/FindCurses.cmake
index 64600c6..5d9952f 100644
--- a/Modules/FindCurses.cmake
+++ b/Modules/FindCurses.cmake
@@ -5,7 +5,11 @@
 FindCurses
 ----------
 
-Finds the curses or ncurses library.
+Finds the curses or ncurses library:
+
+.. code-block:: cmake
+
+  find_package(Curses [...])
 
 Curses is a terminal control library for Unix-like systems, used to build text
 user interface (TUI) applications.  Originally developed in 1978, it has since
diff --git a/Modules/FindCxxTest.cmake b/Modules/FindCxxTest.cmake
index 37f1e7a..4e46cf4 100644
--- a/Modules/FindCxxTest.cmake
+++ b/Modules/FindCxxTest.cmake
@@ -6,7 +6,11 @@
 -----------
 
 Finds `CxxTest`_, a C++ unit testing framework suite, and provides a helper
-command to create test runners and integrate them with CTest.
+command to create test runners and integrate them with CTest:
+
+.. code-block:: cmake
+
+  find_package(CxxTest [...])
 
 .. _`CxxTest`: https://github.com/CxxTest/cxxtest
 
diff --git a/Modules/FindCygwin.cmake b/Modules/FindCygwin.cmake
index ba26980..38db22d 100644
--- a/Modules/FindCygwin.cmake
+++ b/Modules/FindCygwin.cmake
@@ -6,7 +6,11 @@
 ----------
 
 Finds Cygwin, a POSIX-compatible environment that runs natively on Microsoft
-Windows.
+Windows:
+
+.. code-block:: cmake
+
+  find_package(Cygwin [...])
 
 .. note::
 
@@ -30,7 +34,7 @@
 Finding the Cygwin installation and using its path in a custom find module:
 
 .. code-block:: cmake
-  :caption: FindFoo.cmake
+  :caption: ``FindFoo.cmake``
 
   find_package(Cygwin)
   find_program(Foo_EXECUTABLE NAMES foo PATHS ${CYGWIN_INSTALL_PATH}/bin)
diff --git a/Modules/FindDart.cmake b/Modules/FindDart.cmake
index 96cce45..252b6fa 100644
--- a/Modules/FindDart.cmake
+++ b/Modules/FindDart.cmake
@@ -8,10 +8,20 @@
 .. deprecated:: 3.27
   This module is available only if policy :policy:`CMP0145` is not set to ``NEW``.
 
-Find DART
+Finds DART:
 
-This module looks for the dart testing software and sets DART_ROOT to
+.. code-block:: cmake
+
+  find_package(DART [...])
+
+This module looks for the dart testing software and sets ``DART_ROOT`` to
 point to where it found it.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+``DART_ROOT``
+  The path to the Dart root installation.
 #]=======================================================================]
 
 if(_FindDart_testing)
diff --git a/Modules/FindDevIL.cmake b/Modules/FindDevIL.cmake
index 9e195d3..019d45f 100644
--- a/Modules/FindDevIL.cmake
+++ b/Modules/FindDevIL.cmake
@@ -5,7 +5,15 @@
 FindDevIL
 ---------
 
-Finds the Developer's Image Library, `DevIL <https://openil.sourceforge.net/>`_.
+Finds the Developer's Image Library, `DevIL <https://openil.sourceforge.net/>`_:
+
+.. code-block:: cmake
+
+  find_package(DevIL [<version>] [...])
+
+.. versionadded:: 4.2
+  Support for the ``<version>`` argument in the :command:`find_package`
+  call.  Version can be also specified as a range.
 
 The DevIL package internally consists of the following libraries, all
 distributed as part of the same release:
@@ -58,8 +66,13 @@
 This module defines the following variables:
 
 ``DevIL_FOUND``
-  Boolean indicating whether the DevIL package is found, including the IL and
-  ILU libraries.
+  Boolean indicating whether the (requested version of) DevIL package is
+  found, including the IL and ILU libraries.
+
+``DevIL_VERSION``
+  .. versionadded:: 4.2
+
+  The version of the DevIL found.
 
 ``DevIL_ILUT_FOUND``
   .. versionadded:: 3.21
@@ -109,8 +122,8 @@
   target_link_libraries(app PRIVATE DevIL::ILUT)
 #]=======================================================================]
 
-# TODO: Add version support.
-# Tested under Linux and Windows (MSVC)
+cmake_policy(PUSH)
+cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n>
 
 include(FindPackageHandleStandardArgs)
 
@@ -119,35 +132,62 @@
   DOC "The path to the directory that contains il.h"
 )
 
-#message("IL_INCLUDE_DIR is ${IL_INCLUDE_DIR}")
-
 find_library(IL_LIBRARIES
   NAMES IL DEVIL
   PATH_SUFFIXES libx32 lib64 lib lib32
   DOC "The file that corresponds to the base il library."
 )
 
-#message("IL_LIBRARIES is ${IL_LIBRARIES}")
-
 find_library(ILUT_LIBRARIES
   NAMES ILUT
   PATH_SUFFIXES libx32 lib64 lib lib32
   DOC "The file that corresponds to the il (system?) utility library."
 )
 
-#message("ILUT_LIBRARIES is ${ILUT_LIBRARIES}")
-
 find_library(ILU_LIBRARIES
   NAMES ILU
   PATH_SUFFIXES libx32 lib64 lib lib32
   DOC "The file that corresponds to the il utility library."
 )
 
-#message("ILU_LIBRARIES is ${ILU_LIBRARIES}")
+# Get version.
+block(PROPAGATE DevIL_VERSION)
+  if(IL_INCLUDE_DIR AND EXISTS "${IL_INCLUDE_DIR}/il.h")
+    set(regex "^[ \t]*#[ \t]*define[ \t]+IL_VERSION[ \t]+([0-9]+)[ \t]*$")
 
-find_package_handle_standard_args(DevIL DEFAULT_MSG
-                                  IL_LIBRARIES ILU_LIBRARIES
-                                  IL_INCLUDE_DIR)
+    file(STRINGS ${IL_INCLUDE_DIR}/il.h result REGEX "${regex}")
+
+    if(result MATCHES "${regex}")
+      set(DevIL_VERSION "${CMAKE_MATCH_1}")
+
+      math(EXPR DevIL_VERSION_MAJOR "${DevIL_VERSION} / 100")
+      math(EXPR DevIL_VERSION_MINOR "${DevIL_VERSION} / 10 % 10")
+      math(EXPR DevIL_VERSION_PATCH "${DevIL_VERSION} % 10")
+
+      set(DevIL_VERSION "")
+      foreach(part MAJOR MINOR PATCH)
+        if(DevIL_VERSION)
+          string(APPEND ".${DevIL_VERSION_${part}}")
+        else()
+          set(DevIL_VERSION "${DevIL_VERSION_${part}}")
+        endif()
+
+        set(
+          DevIL_VERSION
+          "${DevIL_VERSION_MAJOR}.${DevIL_VERSION_MINOR}.${DevIL_VERSION_PATCH}"
+        )
+      endforeach()
+    endif()
+  endif()
+endblock()
+
+find_package_handle_standard_args(
+  DevIL
+  REQUIRED_VARS IL_LIBRARIES ILU_LIBRARIES IL_INCLUDE_DIR
+  VERSION_VAR DevIL_VERSION
+  HANDLE_VERSION_RANGE
+)
+
 # provide legacy variable for compatibility
 set(IL_FOUND ${DevIL_FOUND})
 
@@ -183,3 +223,5 @@
     target_link_libraries(DevIL::ILUT INTERFACE DevIL::ILU)
   endif()
 endif()
+
+cmake_policy(POP)
diff --git a/Modules/FindDoxygen.cmake b/Modules/FindDoxygen.cmake
index 2d43099..c417b20 100644
--- a/Modules/FindDoxygen.cmake
+++ b/Modules/FindDoxygen.cmake
@@ -11,7 +11,7 @@
 
 .. code-block:: cmake
 
-  find_package(Doxygen [<version>] [...] [COMPONENTS <components>...] [...])
+  find_package(Doxygen [<version>] [COMPONENTS <components>...] [...])
 
 Components
 ^^^^^^^^^^
@@ -95,7 +95,9 @@
   the ``DOXYGEN_FOUND`` variable is also set, except it has boolean value of
   ``YES`` or ``NO``.
 
-``DOXYGEN_VERSION``
+``Doxygen_VERSION``
+  .. versionadded:: 4.2
+
   The version of Doxygen found (as reported by ``doxygen --version``).
 
 Commands
@@ -529,6 +531,12 @@
   (i.e. without specifying components) it prevents this find module from
   searching for Graphviz's ``dot`` utility.
 
+``DOXYGEN_VERSION``
+  .. deprecated:: 4.2
+    Superseded by the ``Doxygen_VERSION``.
+
+  The version of Doxygen found.
+
 Examples
 ^^^^^^^^
 
@@ -653,7 +661,7 @@
 
 In the following example, a custom ``Doxyfile`` configuration file is created
 in the current binary directory (:variable:`CMAKE_CURRENT_BINARY_DIR`) prior
-to calling the ``doxygen_add_doxs()``.  This allows project-specific
+to calling the ``doxygen_add_docs()``.  This allows project-specific
 configuration tags to be customized as needed:
 
 .. code-block:: cmake
@@ -664,7 +672,7 @@
   if(Doxygen_FOUND)
     configure_file(Doxyfile.in Doxyfile)
 
-    doxygen_add_doxs(
+    doxygen_add_docs(
       example_docs
       foo.c bar.c
       ALL
@@ -765,7 +773,8 @@
     mark_as_advanced(DOXYGEN_EXECUTABLE)
 
     if(DOXYGEN_EXECUTABLE)
-        _Doxygen_get_version(DOXYGEN_VERSION _Doxygen_version_result "${DOXYGEN_EXECUTABLE}")
+        _Doxygen_get_version(Doxygen_VERSION _Doxygen_version_result "${DOXYGEN_EXECUTABLE}")
+        set(DOXYGEN_VERSION "${Doxygen_VERSION}")
 
         if(_Doxygen_version_result)
             if(NOT Doxygen_FIND_QUIETLY)
@@ -959,7 +968,7 @@
 find_package_handle_standard_args(
     Doxygen
     REQUIRED_VARS DOXYGEN_EXECUTABLE
-    VERSION_VAR DOXYGEN_VERSION
+    VERSION_VAR Doxygen_VERSION
     HANDLE_VERSION_RANGE
     HANDLE_COMPONENTS
 )
diff --git a/Modules/FindEXPAT.cmake b/Modules/FindEXPAT.cmake
index dd45e58..ece3fcc 100644
--- a/Modules/FindEXPAT.cmake
+++ b/Modules/FindEXPAT.cmake
@@ -5,8 +5,13 @@
 FindEXPAT
 ---------
 
-Finds the native Expat headers and library.  Expat is a stream-oriented XML
-parser library written in C.
+Finds the native Expat headers and library:
+
+.. code-block:: cmake
+
+  find_package(EXPAT [<version>] [...])
+
+Expat is a stream-oriented XML parser library written in C.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -22,15 +27,22 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
+
+``EXPAT_FOUND``
+  Boolean indicating whether (the requested version of) Expat is found.
+
+``EXPAT_VERSION``
+  .. versionadded:: 4.2
+
+  The version of Expat found.
 
 ``EXPAT_INCLUDE_DIRS``
   Include directories containing ``expat.h`` and related headers needed to use
   Expat.
+
 ``EXPAT_LIBRARIES``
   Libraries needed to link against to use Expat.
-``EXPAT_FOUND``
-  Boolean indicating whether the Expat is found.
 
 Hints
 ^^^^^
@@ -46,6 +58,17 @@
 
     Implemented on non-Windows platforms.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``EXPAT_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``EXPAT_VERSION``.
+
+  The version of Expat found.
+
 Examples
 ^^^^^^^^
 
@@ -135,25 +158,26 @@
   file(STRINGS "${EXPAT_INCLUDE_DIR}/expat.h" expat_version_str
     REGEX "^#[\t ]*define[\t ]+XML_(MAJOR|MINOR|MICRO)_VERSION[\t ]+[0-9]+$")
 
-  unset(EXPAT_VERSION_STRING)
+  unset(EXPAT_VERSION)
   foreach(VPART MAJOR MINOR MICRO)
     foreach(VLINE ${expat_version_str})
       if(VLINE MATCHES "^#[\t ]*define[\t ]+XML_${VPART}_VERSION[\t ]+([0-9]+)$")
         set(EXPAT_VERSION_PART "${CMAKE_MATCH_1}")
-        if(EXPAT_VERSION_STRING)
-          string(APPEND EXPAT_VERSION_STRING ".${EXPAT_VERSION_PART}")
+        if(EXPAT_VERSION)
+          string(APPEND EXPAT_VERSION ".${EXPAT_VERSION_PART}")
         else()
-          set(EXPAT_VERSION_STRING "${EXPAT_VERSION_PART}")
+          set(EXPAT_VERSION "${EXPAT_VERSION_PART}")
         endif()
       endif()
     endforeach()
   endforeach()
+  set(EXPAT_VERSION_STRING ${EXPAT_VERSION})
 endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(EXPAT
                                   REQUIRED_VARS EXPAT_LIBRARY EXPAT_INCLUDE_DIR
-                                  VERSION_VAR EXPAT_VERSION_STRING)
+                                  VERSION_VAR EXPAT_VERSION)
 
 # Copy the results to the output variables and target.
 if(EXPAT_FOUND)
diff --git a/Modules/FindFLEX.cmake b/Modules/FindFLEX.cmake
index 11c53a9..a25b083 100644
--- a/Modules/FindFLEX.cmake
+++ b/Modules/FindFLEX.cmake
@@ -10,7 +10,7 @@
 
 .. code-block:: cmake
 
-  find_package(FLEX [<version>] ...)
+  find_package(FLEX [<version>] [...])
 
 Flex generates lexical analyzers, also known as *scanners* or *lexers*.  It also
 includes a runtime library (``fl``) that supplies support functions for the
diff --git a/Modules/FindFLTK.cmake b/Modules/FindFLTK.cmake
index 6b3438c..adeb57b 100644
--- a/Modules/FindFLTK.cmake
+++ b/Modules/FindFLTK.cmake
@@ -6,7 +6,11 @@
 --------
 
 Finds the Fast Light Toolkit (FLTK), a cross-platform toolkit for GUI
-development.
+development:
+
+.. code-block:: cmake
+
+  find_package(FLTK [...])
 
 FLTK uses CMake-based build system and provides a package configuration file for
 projects to find it.  As of its 1.4.0 version it also provides
@@ -18,8 +22,8 @@
 documentation for more information, how to use FLTK with CMake.
 
 .. versionadded:: 3.11
-  Debug and Release library variants are found separately and use
-  per-configuration variables.
+  Debug and release (optimized) library variants are found separately and use
+  :ref:`per-configuration <Build Configurations>` variables.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
diff --git a/Modules/FindFLTK2.cmake b/Modules/FindFLTK2.cmake
index c839d3f..f70c0f0 100644
--- a/Modules/FindFLTK2.cmake
+++ b/Modules/FindFLTK2.cmake
@@ -14,7 +14,11 @@
   modern versions, use the :module:`FindFLTK` module instead.
 
 Finds the Fast Light Toolkit (FLTK) version 2.x, a cross-platform toolkit for
-GUI development.
+GUI development:
+
+.. code-block:: cmake
+
+  find_package(FLTK2 [...])
 
 Result Variables
 ^^^^^^^^^^^^^^^^
diff --git a/Modules/FindFontconfig.cmake b/Modules/FindFontconfig.cmake
index 218ad2f..e5fccb6 100644
--- a/Modules/FindFontconfig.cmake
+++ b/Modules/FindFontconfig.cmake
@@ -7,7 +7,11 @@
 
 .. versionadded:: 3.14
 
-Finds Fontconfig, a library for font configuration and customization.
+Finds Fontconfig, a library for font configuration and customization:
+
+.. code-block:: cmake
+
+  find_package(Fontconfig [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
diff --git a/Modules/FindFreetype.cmake b/Modules/FindFreetype.cmake
index 0a4d9a3..d2be44f 100644
--- a/Modules/FindFreetype.cmake
+++ b/Modules/FindFreetype.cmake
@@ -5,7 +5,14 @@
 FindFreetype
 ------------
 
-Finds the FreeType font renderer library.
+Finds the FreeType font renderer library:
+
+.. code-block:: cmake
+
+  find_package(Freetype [<version>] [...])
+
+.. versionadded:: 3.7
+  Debug and Release (optimized) library variants are found separately.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -24,9 +31,14 @@
 This module defines the following variables:
 
 ``Freetype_FOUND``
-  Boolean indicating whether the (requested version of) Freetype is found.  For
-  backward compatibility, the ``FREETYPE_FOUND`` variable is also set to the
-  same value.
+  Boolean indicating whether (the requested version of) Freetype is found.
+  For backward compatibility, the ``FREETYPE_FOUND`` variable is also set
+  to the same value.
+
+``Freetype_VERSION``
+  .. versionadded:: 4.2
+
+  The version of Freetype found.
 
 ``FREETYPE_INCLUDE_DIRS``
   Include directories containing headers needed to use Freetype.  This is the
@@ -36,9 +48,6 @@
 ``FREETYPE_LIBRARIES``
   Libraries needed to link against for using Freetype.
 
-``FREETYPE_VERSION_STRING``
-  The version of Freetype found.
-
 .. versionadded:: 3.7
   Debug and Release library variants are found separately.
 
@@ -62,6 +71,17 @@
   The user may set this environment variable to the root directory of a Freetype
   installation to find Freetype in non-standard locations.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``FREETYPE_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``Freetype_VERSION``.
+
+  The version of Freetype found.
+
 Examples
 ^^^^^^^^
 
@@ -170,20 +190,21 @@
   file(STRINGS "${FREETYPE_H}" freetype_version_str
        REGEX "^#[\t ]*define[\t ]+FREETYPE_(MAJOR|MINOR|PATCH)[\t ]+[0-9]+$")
 
-  unset(FREETYPE_VERSION_STRING)
+  unset(Freetype_VERSION)
   foreach(VPART MAJOR MINOR PATCH)
     foreach(VLINE ${freetype_version_str})
       if(VLINE MATCHES "^#[\t ]*define[\t ]+FREETYPE_${VPART}[\t ]+([0-9]+)$")
         set(FREETYPE_VERSION_PART "${CMAKE_MATCH_1}")
-        if(FREETYPE_VERSION_STRING)
-          string(APPEND FREETYPE_VERSION_STRING ".${FREETYPE_VERSION_PART}")
+        if(Freetype_VERSION)
+          string(APPEND Freetype_VERSION ".${FREETYPE_VERSION_PART}")
         else()
-          set(FREETYPE_VERSION_STRING "${FREETYPE_VERSION_PART}")
+          set(Freetype_VERSION "${FREETYPE_VERSION_PART}")
         endif()
         unset(FREETYPE_VERSION_PART)
       endif()
     endforeach()
   endforeach()
+  set(FREETYPE_VERSION_STRING ${Freetype_VERSION})
 endif()
 
 include(FindPackageHandleStandardArgs)
@@ -194,7 +215,7 @@
     FREETYPE_LIBRARY
     FREETYPE_INCLUDE_DIRS
   VERSION_VAR
-    FREETYPE_VERSION_STRING
+    Freetype_VERSION
 )
 
 mark_as_advanced(
diff --git a/Modules/FindGCCXML.cmake b/Modules/FindGCCXML.cmake
index fdab959..cf4a96f 100644
--- a/Modules/FindGCCXML.cmake
+++ b/Modules/FindGCCXML.cmake
@@ -7,14 +7,30 @@
 
 .. versionchanged:: 4.1
   This module is available only if policy :policy:`CMP0188` is not set to ``NEW``.
-  Port projects to search for CastXML by calling ``find_program`` directly.
+  Port projects to search for CastXML by calling :command:`find_program` directly.
 
-Find the GCC-XML front-end executable.
+Finds the GCC-XML front-end executable:
 
-This module will define the following variables:
+.. code-block:: cmake
+
+  find_package(GCCXML [...])
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+The following cache variables may also be set:
 
 ``GCCXML``
   The GCC-XML front-end executable.
+
+Examples
+^^^^^^^^
+
+In new code, find CastXML with :command:`find_program` instead:
+
+.. code-block:: cmake
+
+  find_program(CASTXML_EXECUTABLE castxml)
 #]=======================================================================]
 
 cmake_policy(GET CMP0188 _FindGCCXML_CMP0188)
diff --git a/Modules/FindGDAL.cmake b/Modules/FindGDAL.cmake
index b952949..d5f42b5 100644
--- a/Modules/FindGDAL.cmake
+++ b/Modules/FindGDAL.cmake
@@ -5,61 +5,86 @@
 FindGDAL
 --------
 
-Find Geospatial Data Abstraction Library (GDAL).
-
 .. deprecated:: 4.0
   GDAL 3.5 and above provide a ``GDALConfig.cmake`` package configuration file.
   Call ``find_package(GDAL CONFIG)`` to find it directly and avoid using this
   find module.  For further details, see `GDAL's documentation on CMake
   integration <https://gdal.org/en/latest/development/cmake.html>`_.
 
+Finds Geospatial Data Abstraction Library (GDAL):
+
+.. code-block:: cmake
+
+  find_package(GDAL [<version>] [...])
+
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.14
+This module provides the following :ref:`Imported Targets`:
 
-This module defines :prop_tgt:`IMPORTED` target ``GDAL::GDAL``
-if GDAL has been found.
+``GDAL::GDAL``
+  .. versionadded:: 3.14
+
+  Target encapsulating the GDAL usage requirements, available only if GDAL
+  has been found.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module will set the following variables in your project:
+This module defines the following variables:
 
 ``GDAL_FOUND``
-  True if GDAL is found.
-``GDAL_INCLUDE_DIRS``
-  Include directories for GDAL headers.
-``GDAL_LIBRARIES``
-  Libraries to link to GDAL.
+  Boolean indicating whether (the requested version of) GDAL is found.
+
 ``GDAL_VERSION``
   .. versionadded:: 3.14
-    The version of GDAL found.
 
-Cache variables
+  The version of GDAL found.
+
+``GDAL_INCLUDE_DIRS``
+  Include directories for GDAL headers.
+
+``GDAL_LIBRARIES``
+  Libraries to link to GDAL.
+
+Cache Variables
 ^^^^^^^^^^^^^^^
 
 The following cache variables may also be set:
 
+``GDAL_INCLUDE_DIR``
+  The directory containing ``<gdal.h>``.
+
 ``GDAL_LIBRARY``
   The libgdal library file.
-``GDAL_INCLUDE_DIR``
-  The directory containing ``gdal.h``.
 
 Hints
 ^^^^^
 
-Set ``GDAL_DIR`` or ``GDAL_ROOT`` in the environment to specify the
-GDAL installation prefix.
-
 The following variables may be set to modify the search strategy:
 
+``GDAL_DIR`` or ``GDAL_ROOT``
+  Set one of these environment variables to specify the GDAL installation
+  prefix.
+
 ``FindGDAL_SKIP_GDAL_CONFIG``
-  If set, ``gdal-config`` will not be used. This can be useful if there are
+  If set, ``gdal-config`` will not be used.  This can be useful if there are
   GDAL libraries built with autotools (which provide the tool) and CMake (which
   do not) in the same environment.
+
 ``GDAL_ADDITIONAL_LIBRARY_VERSIONS``
   Extra versions of library names to search for.
+
+Examples
+^^^^^^^^
+
+Finding GDAL in config mode without using this module and linking its
+imported target to a project target:
+
+.. code-block:: cmake
+
+  find_package(GDAL CONFIG)
+  target_link_libraries(example PRIVATE GDAL::GDAL)
 #]=======================================================================]
 
 # $GDALDIR is an environment variable that would
diff --git a/Modules/FindGIF.cmake b/Modules/FindGIF.cmake
index 585b846..e3a751b 100644
--- a/Modules/FindGIF.cmake
+++ b/Modules/FindGIF.cmake
@@ -5,7 +5,11 @@
 FindGIF
 -------
 
-Finds the Graphics Interchange Format (GIF) library (``giflib``).
+Finds the Graphics Interchange Format (GIF) library (``giflib``):
+
+.. code-block:: cmake
+
+  find_package(GIF [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -21,19 +25,22 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``GIF_FOUND``
-  Boolean indicating whether the GIF library was found.
-``GIF_INCLUDE_DIRS``
-  Include directories needed to use the GIF library.
-``GIF_LIBRARIES``
-  Libraries needed to link to the GIF library.
+  Boolean indicating whether (the requested version of) GIF library was found.
+
 ``GIF_VERSION``
   Version string of the GIF library found (for example, ``5.1.4``).  For GIF
   library versions prior to 4.1.6, version string will be set only to ``3`` or
   ``4`` as these versions did not provide version information in their headers.
 
+``GIF_INCLUDE_DIRS``
+  Include directories needed to use the GIF library.
+
+``GIF_LIBRARIES``
+  Libraries needed to link to the GIF library.
+
 Cache Variables
 ^^^^^^^^^^^^^^^
 
@@ -41,6 +48,7 @@
 
 ``GIF_INCLUDE_DIR``
   Directory containing the ``gif_lib.h`` and other GIF library headers.
+
 ``GIF_LIBRARY``
   Path to the GIF library.
 
diff --git a/Modules/FindGLEW.cmake b/Modules/FindGLEW.cmake
index 03d19bf..b9fe261 100644
--- a/Modules/FindGLEW.cmake
+++ b/Modules/FindGLEW.cmake
@@ -5,7 +5,11 @@
 FindGLEW
 --------
 
-Finds the OpenGL Extension Wrangler Library (GLEW).
+Finds the OpenGL Extension Wrangler Library (GLEW):
+
+.. code-block:: cmake
+
+  find_package(GLEW [<version>] [...])
 
 GLEW is a cross-platform C/C++ library that helps manage OpenGL extensions by
 providing efficient run-time mechanisms to query and load OpenGL functionality
@@ -53,7 +57,7 @@
 This module defines the following variables:
 
 ``GLEW_FOUND``
-  Boolean indicating whether GLEW is found.
+  Boolean indicating whether (the requested version of) GLEW is found.
 
 ``GLEW_VERSION``
   .. versionadded:: 3.15
diff --git a/Modules/FindGLUT.cmake b/Modules/FindGLUT.cmake
index e29758d..5b773cd 100644
--- a/Modules/FindGLUT.cmake
+++ b/Modules/FindGLUT.cmake
@@ -5,8 +5,13 @@
 FindGLUT
 --------
 
-Finds the OpenGL Utility Toolkit (GLUT) library, which provides a simple API for
-creating windows, handling input, and managing events in OpenGL applications.
+Finds the OpenGL Utility Toolkit (GLUT) library, which provides a simple API
+for creating windows, handling input, and managing events in OpenGL
+applications:
+
+.. code-block:: cmake
+
+  find_package(GLUT [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
diff --git a/Modules/FindGSL.cmake b/Modules/FindGSL.cmake
index a3cd654..db9f737 100644
--- a/Modules/FindGSL.cmake
+++ b/Modules/FindGSL.cmake
@@ -7,7 +7,11 @@
 
 .. versionadded:: 3.2
 
-Finds the native GNU Scientific Library (GSL) includes and libraries.
+Finds the native GNU Scientific Library (GSL) includes and libraries:
+
+.. code-block:: cmake
+
+  find_package(GSL [<version>] [...])
 
 The GNU Scientific Library (GSL) is a numerical library for C and C++
 programmers. It is free software under the GNU General Public
@@ -16,43 +20,31 @@
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-If GSL is found, this module defines the following :ref:`Imported Targets`:
+This module provides the following :ref:`Imported Targets`:
 
 ``GSL::gsl``
-  The main GSL library that provides all usage requirements to use GSL.
+  Target encapsulating the main GSL library and all usage requirements,
+  available only if GSL is found.
+
 ``GSL::gslcblas``
-  The CBLAS support library used by GSL.  It is linked also into the
-  ``GSL::gsl`` target but provided separately for granularity.
+  Target encapsulating the usage requirements of the CBLAS support library
+  used by GSL.  This target is available if GSL is found.  It is linked also
+  into the ``GSL::gsl`` target but provided separately for granularity.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module will set the following variables in the project:
+This module defines the following variables:
 
 ``GSL_FOUND``
-  True if GSL is found on the local system.
+  Boolean indicating whether (the requested version of) GSL is found on the
+  local system.
+``GSL_VERSION``
+  The version of the discovered GSL installation.
 ``GSL_INCLUDE_DIRS``
   Directory containing GSL header files.
 ``GSL_LIBRARIES``
   The GSL libraries.
-``GSL_VERSION``
-  The version of the discovered GSL installation.
-
-Hints
-^^^^^
-
-``GSL_ROOT_DIR``
-  Set this variable to a directory that contains a GSL installation.
-
-  If this variable is not set, this module will use pkg-config and default paths
-  to find GSL.  If this variable is provided, then this module expects to find
-  libraries at ``${GSL_ROOT_DIR}/lib`` and the GSL headers at
-  ``${GSL_ROOT_DIR}/include/gsl``.
-
-  The library directory may optionally provide Release and Debug folders.  If
-  available, the libraries named ``gsld``, ``gslblasd`` or ``cblasd`` are
-  recognized as debug libraries.  For Unix-like systems, this module will also
-  use ``gsl-config`` (if found) to aid in the discovery of GSL.
 
 Cache Variables
 ^^^^^^^^^^^^^^^
@@ -72,6 +64,24 @@
 ``GSL_LIBRARY_DEBUG``
   Location of the debug GSL library (if any).
 
+Hints
+^^^^^
+
+This module accepts the following variables:
+
+``GSL_ROOT_DIR``
+  Set this variable to a directory that contains a GSL installation.
+
+  If this variable is not set, this module will use pkg-config and default paths
+  to find GSL.  If this variable is provided, then this module expects to find
+  libraries at ``${GSL_ROOT_DIR}/lib`` and the GSL headers at
+  ``${GSL_ROOT_DIR}/include/gsl``.
+
+  The library directory may optionally provide Release and Debug folders.  If
+  available, the libraries named ``gsld``, ``gslblasd`` or ``cblasd`` are
+  recognized as debug libraries.  For Unix-like systems, this module will also
+  use ``gsl-config`` (if found) to aid in the discovery of GSL.
+
 Examples
 ^^^^^^^^
 
@@ -174,8 +184,6 @@
 endif()
 
 #=============================================================================
-# handle the QUIETLY and REQUIRED arguments and set GSL_FOUND to TRUE if all
-# listed variables are TRUE
 find_package_handle_standard_args( GSL
   REQUIRED_VARS
     GSL_INCLUDE_DIR
diff --git a/Modules/FindGettext.cmake b/Modules/FindGettext.cmake
index 71d41e0..49f27b7 100644
--- a/Modules/FindGettext.cmake
+++ b/Modules/FindGettext.cmake
@@ -10,7 +10,7 @@
 
 .. code-block:: cmake
 
-  find_package(Gettext [<version>] ...)
+  find_package(Gettext [<version>] [...])
 
 GNU gettext is a system for internationalization (i18n) and localization
 (l10n), consisting of command-line tools and a runtime library (``libintl``).
@@ -40,7 +40,9 @@
   backward compatibility, the ``GETTEXT_FOUND`` variable is also set to the same
   value.
 
-``GETTEXT_VERSION_STRING``
+``Gettext_VERSION``
+  .. versionadded:: 4.2
+
   The version of gettext found.
 
 Cache Variables
@@ -194,6 +196,17 @@
     For better control over build and installation behavior, use
     :command:`gettext_process_po_files` instead.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``GETTEXT_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``Gettext_VERSION``.
+
+  The version of gettext found.
+
 Examples
 ^^^^^^^^
 
@@ -398,7 +411,8 @@
   get_filename_component(msgmerge_name ${GETTEXT_MSGMERGE_EXECUTABLE} NAME)
   get_filename_component(msgmerge_namewe ${GETTEXT_MSGMERGE_EXECUTABLE} NAME_WE)
   if(gettext_version MATCHES "^(${msgmerge_name}|${msgmerge_namewe}) \\([^\\)]*\\) ([0-9\\.]+[^ \n]*)")
-    set(GETTEXT_VERSION_STRING "${CMAKE_MATCH_2}")
+    set(Gettext_VERSION "${CMAKE_MATCH_2}")
+    set(GETTEXT_VERSION_STRING "${Gettext_VERSION}")
   endif()
   unset(gettext_version)
   unset(msgmerge_name)
@@ -408,7 +422,7 @@
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Gettext
                                   REQUIRED_VARS GETTEXT_MSGMERGE_EXECUTABLE GETTEXT_MSGFMT_EXECUTABLE
-                                  VERSION_VAR GETTEXT_VERSION_STRING)
+                                  VERSION_VAR Gettext_VERSION)
 
 function(_GETTEXT_GET_UNIQUE_TARGET_NAME _name _unique_name)
   set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}")
diff --git a/Modules/FindGnuTLS.cmake b/Modules/FindGnuTLS.cmake
index d9d8260..14c64d7 100644
--- a/Modules/FindGnuTLS.cmake
+++ b/Modules/FindGnuTLS.cmake
@@ -5,12 +5,17 @@
 FindGnuTLS
 ----------
 
-Finds the GNU Transport Layer Security library (GnuTLS).  The GnuTLS
-package includes the main libraries (libgnutls and libdane), as well as the
-optional gnutls-openssl compatibility extra library.  They are all distributed
-as part of the same release.  This module checks for the presence of the main
-libgnutls library and provides usage requirements for integrating GnuTLS into
-CMake projects.
+Finds the GNU Transport Layer Security library (GnuTLS):
+
+.. code-block:: cmake
+
+  find_package(GnuTLS [<version>] [...])
+
+The GnuTLS package includes the main libraries (libgnutls and libdane), as
+well as the optional gnutls-openssl compatibility extra library.  They are
+all distributed as part of the same release.  This module checks for the
+presence of the main libgnutls library and provides usage requirements for
+integrating GnuTLS into CMake projects.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -29,12 +34,12 @@
 This module defines the following variables:
 
 ``GnuTLS_FOUND``
-  Boolean indicating whether the (requested version of) GnuTLS is found.  For
+  Boolean indicating whether (the requested version of) GnuTLS is found.  For
   backward compatibility, the ``GNUTLS_FOUND`` variable is also set to the same
   value.
 
-``GNUTLS_VERSION``
-  .. versionadded:: 3.16
+``GnuTLS_VERSION``
+  .. versionadded:: 4.2
 
   The version of GnuTLS found.
 
@@ -61,13 +66,16 @@
 Deprecated Variables
 ^^^^^^^^^^^^^^^^^^^^
 
-These variables are provided for backward compatibility:
+The following variables are provided for backward compatibility:
 
 ``GNUTLS_VERSION_STRING``
   .. deprecated:: 3.16
-    Superseded by ``GNUTLS_VERSION``.
+    Use the ``GnuTLS_VERSION``, which has the same value.
 
-  The version of GnuTLS found.
+``GNUTLS_VERSION``
+  .. versionadded:: 3.16
+  .. deprecated:: 4.2
+    Use the ``GnuTLS_VERSION``, which has the same value.
 
 Examples
 ^^^^^^^^
@@ -80,6 +88,9 @@
   target_link_libraries(project_target PRIVATE GnuTLS::GnuTLS)
 #]=======================================================================]
 
+cmake_policy(PUSH)
+cmake_policy(SET CMP0159 NEW) # file(STRINGS) with REGEX updates CMAKE_MATCH_<n>
+
 if (GNUTLS_INCLUDE_DIR AND GNUTLS_LIBRARY)
   # in cache already
   set(gnutls_FIND_QUIETLY TRUE)
@@ -94,9 +105,6 @@
     pkg_check_modules(PC_GNUTLS QUIET gnutls)
   endif()
   set(GNUTLS_DEFINITIONS ${PC_GNUTLS_CFLAGS_OTHER})
-  set(GNUTLS_VERSION ${PC_GNUTLS_VERSION})
-  # keep for backward compatibility
-  set(GNUTLS_VERSION_STRING ${PC_GNUTLS_VERSION})
 endif ()
 
 find_path(GNUTLS_INCLUDE_DIR gnutls/gnutls.h
@@ -113,10 +121,43 @@
 
 mark_as_advanced(GNUTLS_INCLUDE_DIR GNUTLS_LIBRARY)
 
+if(GNUTLS_INCLUDE_DIR AND EXISTS "${GNUTLS_INCLUDE_DIR}/gnutls/gnutls.h")
+  file(
+    STRINGS
+    "${GNUTLS_INCLUDE_DIR}/gnutls/gnutls.h"
+    gnutls_version
+    # GnuTLS versions prior to 2.7.2 defined LIBGNUTLS_VERSION instead of the
+    # current GNUTLS_VERSION.
+    REGEX "^#define[\t ]+(LIB)?GNUTLS_VERSION[\t ]+\".*\""
+  )
+
+  string(
+    REGEX REPLACE
+    "^.*GNUTLS_VERSION[\t ]+\"([^\"]*)\".*$"
+    "\\1"
+    GnuTLS_VERSION
+    "${gnutls_version}"
+  )
+  unset(gnutls_version)
+
+  # Fallback to version defined by pkg-config if not successful.
+  if(
+    NOT GnuTLS_VERSION
+    AND PC_GNUTLS_VERSION
+    AND GNUTLS_INCLUDE_DIR IN_LIST PC_GNUTLS_INCLUDE_DIRS
+  )
+    set(GnuTLS_VERSION "${PC_GNUTLS_VERSION}")
+  endif()
+
+  # For backward compatibility.
+  set(GNUTLS_VERSION "${GnuTLS_VERSION}")
+  set(GNUTLS_VERSION_STRING "${GnuTLS_VERSION}")
+endif()
+
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(GnuTLS
                                   REQUIRED_VARS GNUTLS_LIBRARY GNUTLS_INCLUDE_DIR
-                                  VERSION_VAR GNUTLS_VERSION_STRING)
+                                  VERSION_VAR GnuTLS_VERSION)
 
 if(GnuTLS_FOUND)
   set(GNUTLS_LIBRARIES    ${GNUTLS_LIBRARY})
@@ -131,3 +172,5 @@
       IMPORTED_LOCATION "${GNUTLS_LIBRARIES}")
   endif()
 endif()
+
+cmake_policy(POP)
diff --git a/Modules/FindGnuplot.cmake b/Modules/FindGnuplot.cmake
index abbb681..c8e7886 100644
--- a/Modules/FindGnuplot.cmake
+++ b/Modules/FindGnuplot.cmake
@@ -6,18 +6,25 @@
 -----------
 
 Finds the Gnuplot command-line graphing utility for generating two- and
-three-dimensional plots (``gnuplot``).
+three-dimensional plots (``gnuplot``):
+
+.. code-block:: cmake
+
+  find_package(Gnuplot [<version>] [...])
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``Gnuplot_FOUND``
-  Boolean indicating whether Gnuplot has been found.  For backward
-  compatibility, the ``GNUPLOT_FOUND`` variable is also set to the same value.
+  Boolean indicating whether (the requested version of) Gnuplot has been
+  found.  For backward compatibility, the ``GNUPLOT_FOUND`` variable is also
+  set to the same value.
 
-``GNUPLOT_VERSION_STRING``
+``Gnuplot_VERSION``
+  .. versionadded:: 4.2
+
   The version of Gnuplot found.
 
   .. note::
@@ -33,14 +40,28 @@
 ``GNUPLOT_EXECUTABLE``
   Absolute path to the ``gnuplot`` executable.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``GNUPLOT_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``Gnuplot_VERSION``.
+
+  The version of Gnuplot found.
+
 Examples
 ^^^^^^^^
 
-Finding Gnuplot:
+Finding Gnuplot and executing it in a process:
 
 .. code-block:: cmake
 
   find_package(Gnuplot)
+  if(Gnuplot_FOUND)
+    execute_process(COMMAND ${GNUPLOT_EXECUTABLE} --help)
+  endif()
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
@@ -62,8 +83,9 @@
                   ERROR_QUIET
                   OUTPUT_STRIP_TRAILING_WHITESPACE)
 
-    string(REGEX REPLACE "^gnuplot ([0-9\\.]+)( patchlevel )?" "\\1." GNUPLOT_VERSION_STRING "${GNUPLOT_OUTPUT_VARIABLE}")
-    string(REGEX REPLACE "\\.$" "" GNUPLOT_VERSION_STRING "${GNUPLOT_VERSION_STRING}")
+    string(REGEX REPLACE "^gnuplot ([0-9\\.]+)( patchlevel )?" "\\1." Gnuplot_VERSION "${GNUPLOT_OUTPUT_VARIABLE}")
+    string(REGEX REPLACE "\\.$" "" Gnuplot_VERSION "${Gnuplot_VERSION}")
+    set(GNUPLOT_VERSION_STRING "${Gnuplot_VERSION}")
     unset(GNUPLOT_OUTPUT_VARIABLE)
 endif()
 
@@ -73,6 +95,6 @@
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Gnuplot
                                   REQUIRED_VARS GNUPLOT_EXECUTABLE
-                                  VERSION_VAR GNUPLOT_VERSION_STRING)
+                                  VERSION_VAR Gnuplot_VERSION)
 
 mark_as_advanced( GNUPLOT_EXECUTABLE )
diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake
index a49e994..a203858 100644
--- a/Modules/FindHDF5.cmake
+++ b/Modules/FindHDF5.cmake
@@ -10,7 +10,7 @@
 
 .. code-block:: cmake
 
-  find_package(HDF5 [<version>] ... [COMPONENTS <components>...] ...)
+  find_package(HDF5 [<version>] [COMPONENTS <components>...] [...])
 
 If the HDF5 library is built using its CMake-based build system, it will as
 of HDF5 version 1.8.15 provide its own CMake Package Configuration file
@@ -71,8 +71,9 @@
 ``HDF5::HDF5``
   .. versionadded:: 3.19
 
-  Target encapsulating the usage requirements for all found HDF5 libraries
-  (``HDF5_LIBRARIES``), available if HDF5 and all required components are found.
+  Target encapsulating the usage requirements for all found HDF5 binding
+  libraries (``HDF5_LIBRARIES``), available if HDF5 and all required components
+  are found.
 
 ``hdf5::hdf5``
   .. versionadded:: 3.19
diff --git a/Modules/FindHTMLHelp.cmake b/Modules/FindHTMLHelp.cmake
index 76b3dcf..71abbe8 100644
--- a/Modules/FindHTMLHelp.cmake
+++ b/Modules/FindHTMLHelp.cmake
@@ -5,8 +5,12 @@
 FindHTMLHelp
 ------------
 
-This module finds the Microsoft HTML Help Compiler and its API.  It is part of
-the HTML Help Workshop.
+Finds the Microsoft HTML Help Compiler and its API which is part of the HTML
+Help Workshop:
+
+.. code-block:: cmake
+
+  find_package(HTMLHelp [...])
 
 .. note::
 
@@ -17,7 +21,7 @@
 Cache Variables
 ^^^^^^^^^^^^^^^
 
-This module may set the following cache variables:
+The following cache variables may also be set:
 
 ``HTML_HELP_COMPILER``
   Full path to the HTML Help Compiler (``hhc.exe``), used to compile ``.chm``
diff --git a/Modules/FindICU.cmake b/Modules/FindICU.cmake
index 942a0ae..97d766d 100644
--- a/Modules/FindICU.cmake
+++ b/Modules/FindICU.cmake
@@ -7,7 +7,11 @@
 
 .. versionadded:: 3.7
 
-Finds the International Components for Unicode (ICU) libraries and programs.
+Finds the International Components for Unicode (ICU) libraries and programs:
+
+.. code-block:: cmake
+
+  find_package(ICU [<version>] COMPONENTS <components>... [...])
 
 .. versionadded:: 3.11
   Support for static libraries on Windows.
@@ -15,7 +19,13 @@
 Components
 ^^^^^^^^^^
 
-This module supports the following components:
+This module supports components, which can be specified with:
+
+.. code-block:: cmake
+
+  find_package(ICU COMPONENTS <components>...)
+
+The following components are supported:
 
 ``data``
   Finds the ICU Data library.  On Windows, this library component is named
@@ -49,12 +59,8 @@
   all other ICU libraries and is recommended to include when working with ICU
   components.
 
-At least one component should be specified for this module to successfully find
-ICU:
-
-.. code-block:: cmake
-
-  find_package(ICU COMPONENTS <components>...)
+At least one component should be specified for this module to successfully
+find ICU.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -74,13 +80,14 @@
 This module defines the following variables:
 
 ``ICU_FOUND``
-  Boolean indicating whether the main programs and libraries were found.
+  Boolean indicating whether the (requested version of) main ICU programs
+  and libraries were found.
+``ICU_VERSION``
+  The version of the ICU release found.
 ``ICU_INCLUDE_DIRS``
   The include directories containing the ICU headers.
 ``ICU_LIBRARIES``
   Component libraries to be linked.
-``ICU_VERSION``
-  The version of the ICU release found.
 
 ICU programs are defined in the following variables:
 
diff --git a/Modules/FindIce.cmake b/Modules/FindIce.cmake
index 8215674..aec8485 100644
--- a/Modules/FindIce.cmake
+++ b/Modules/FindIce.cmake
@@ -7,7 +7,12 @@
 
 .. versionadded:: 3.1
 
-Finds the Internet Communication Engine (Ice) programs, libraries and datafiles.
+Finds the Internet Communication Engine (Ice) programs, libraries and datafiles:
+
+.. code-block:: cmake
+
+  find_package(Ice [<version>] COMPONENTS <components>... [...])
+
 Ice is an open-source remote procedure call (RPC) framework developed by ZeroC
 and provides SDKs for various languages to develop network applications.
 
diff --git a/Modules/FindIconv.cmake b/Modules/FindIconv.cmake
index a11d746..d49c2db 100644
--- a/Modules/FindIconv.cmake
+++ b/Modules/FindIconv.cmake
@@ -7,9 +7,14 @@
 
 .. versionadded:: 3.11
 
-This module finds the ``iconv()`` POSIX.1 functions on the system.  These
-functions might be provided in the standard C library or externally in the form
-of an additional library.
+Finds the ``iconv()`` POSIX.1 functions on the system:
+
+.. code-block:: cmake
+
+  find_package(Iconv [<version>] [...])
+
+Iconv functions might be provided in the standard C library or externally
+in the form of an additional library.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -26,13 +31,8 @@
 This module defines the following variables:
 
 ``Iconv_FOUND``
-  Boolean indicating if the iconv support was found.
-
-``Iconv_INCLUDE_DIRS``
-  The include directories containing the iconv headers.
-
-``Iconv_LIBRARIES``
-  The iconv libraries to be linked.
+  Boolean indicating whether the (requested version of) iconv support was
+  found.
 
 ``Iconv_VERSION``
   .. versionadded:: 3.21
@@ -53,17 +53,23 @@
 
   The minor version of iconv.
 
-``Iconv_IS_BUILT_IN``
-  A boolean variable indicating whether iconv support is stemming from the C
-  standard library or not.  Even if the C library provides ``iconv()``, the
-  presence of an external ``libiconv`` implementation might lead to this being
-  false.
+``Iconv_INCLUDE_DIRS``
+  The include directories containing the iconv headers.
+
+``Iconv_LIBRARIES``
+  The iconv libraries to be linked.
 
 Cache Variables
 ^^^^^^^^^^^^^^^
 
 The following cache variables may also be set:
 
+``Iconv_IS_BUILT_IN``
+  A boolean variable indicating whether iconv support is stemming from the C
+  standard library or not.  Even if the C library provides ``iconv()``, the
+  presence of an external ``libiconv`` implementation might lead to this being
+  false.
+
 ``Iconv_INCLUDE_DIR``
   The directory containing the iconv headers.
 
diff --git a/Modules/FindIntl.cmake b/Modules/FindIntl.cmake
index cdc6541..4b0808a 100644
--- a/Modules/FindIntl.cmake
+++ b/Modules/FindIntl.cmake
@@ -8,9 +8,15 @@
 .. versionadded:: 3.2
 
 Finds internationalization support that includes message translation functions
-such as ``gettext()``.  These functions originate from the GNU ``libintl``
-library, which is part of the GNU gettext utilities, but may also be provided by
-the standard C library.
+such as ``gettext()``:
+
+.. code-block:: cmake
+
+  find_package(Intl [<version>] [...])
+
+These functions originate from the GNU ``libintl`` library, which is part
+of the GNU gettext utilities, but may also be provided by the standard C
+library.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -28,13 +34,7 @@
 This module defines the following variables:
 
 ``Intl_FOUND``
-  Boolean indicating whether the Intl is found.
-
-``Intl_INCLUDE_DIRS``
-  Include directories containing headers needed to use Intl.
-
-``Intl_LIBRARIES``
-  The libraries needed to link against to use Intl.
+  Boolean indicating whether (the requested version of) Intl is found.
 
 ``Intl_VERSION``
   .. versionadded:: 3.21
@@ -61,23 +61,29 @@
 
   The patch version of Intl found.
 
+``Intl_INCLUDE_DIRS``
+  Include directories containing headers needed to use Intl.
+
+``Intl_LIBRARIES``
+  The libraries needed to link against to use Intl.
+
 Cache Variables
 ^^^^^^^^^^^^^^^
 
 The following cache variables may also be set:
 
-``Intl_INCLUDE_DIR``
-  The directory containing the ``libintl.h`` header file.
-
-``Intl_LIBRARY``
-  The path to the Intl library (if any).
-
 ``Intl_IS_BUILT_IN``
   .. versionadded:: 3.20
 
   Boolean indicating whether the found Intl functionality is provided by the
   standard C library rather than a separate ``libintl`` library.
 
+``Intl_INCLUDE_DIR``
+  The directory containing the ``libintl.h`` header file.
+
+``Intl_LIBRARY``
+  The path to the Intl library (if any).
+
 .. note::
   On some platforms, such as Linux with GNU libc, the gettext functions are
   present in the C standard library and libintl is not required.  The
diff --git a/Modules/FindJNI.cmake b/Modules/FindJNI.cmake
index 10dcc51..477ff7a 100644
--- a/Modules/FindJNI.cmake
+++ b/Modules/FindJNI.cmake
@@ -5,7 +5,11 @@
 FindJNI
 -------
 
-Finds the Java Native Interface (JNI) include directories and libraries.
+Finds the Java Native Interface (JNI) include directories and libraries:
+
+.. code-block:: cmake
+
+  find_package(JNI [<version>] [COMPONENTS <components>...] [...])
 
 JNI enables Java code running in a Java Virtual Machine (JVM) or Dalvik Virtual
 Machine (DVM) on Android to call and be called by native applications and
diff --git a/Modules/FindJPEG.cmake b/Modules/FindJPEG.cmake
index 9d43f58..b44612f 100644
--- a/Modules/FindJPEG.cmake
+++ b/Modules/FindJPEG.cmake
@@ -5,7 +5,11 @@
 FindJPEG
 --------
 
-Finds the Joint Photographic Experts Group (JPEG) library (``libjpeg``).
+Finds the Joint Photographic Experts Group (JPEG) library (``libjpeg``):
+
+.. code-block:: cmake
+
+  find_package(JPEG [<version>] [...])
 
 .. versionchanged:: 3.12
   Debug and Release JPEG library variants are now found separately.
@@ -24,10 +28,15 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``JPEG_FOUND``
-  Boolean indicating whether the JPEG is found.
+  Boolean indicating whether (the requested version of) JPEG library is found.
+
+``JPEG_VERSION``
+  .. versionadded:: 3.12
+
+  The version of JPEG library found.
 
 ``JPEG_INCLUDE_DIRS``
   Include directories containing headers needed to use JPEG.
@@ -35,18 +44,13 @@
 ``JPEG_LIBRARIES``
   Libraries needed to link to JPEG.
 
-``JPEG_VERSION``
-  .. versionadded:: 3.12
-
-  The version of the JPEG library found.
-
 Cache Variables
 ^^^^^^^^^^^^^^^
 
 The following cache variables may also be set:
 
 ``JPEG_INCLUDE_DIR``
-  Directory containing the ``jpeglib.h`` and related header files.
+  Directory containing the ``<jpeglib.h>`` and related header files.
 
 ``JPEG_LIBRARY_RELEASE``
   .. versionadded:: 3.12
@@ -58,13 +62,13 @@
 
   Path to the debug variant of the JPEG library.
 
-Obsolete Variables
-^^^^^^^^^^^^^^^^^^
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
 
-The following legacy variables are provided for backward compatibility:
+The following variables are provided for backward compatibility:
 
 ``JPEG_LIBRARY``
-  .. versionchanged:: 3.12
+  .. deprecated:: 3.12
     This variable has been superseded by the ``JPEG_LIBRARY_RELEASE`` and
     ``JPEG_LIBRARY_DEBUG`` variables.
 
diff --git a/Modules/FindJasper.cmake b/Modules/FindJasper.cmake
index 3902f6d..6fed81b 100644
--- a/Modules/FindJasper.cmake
+++ b/Modules/FindJasper.cmake
@@ -6,7 +6,11 @@
 ----------
 
 Finds the JasPer Image Coding Toolkit for handling image data in a variety of
-formats, such as the JPEG-2000.
+formats, such as the JPEG-2000:
+
+.. code-block:: cmake
+
+  find_package(Jasper [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -25,8 +29,14 @@
 This module defines the following variables:
 
 ``Jasper_FOUND``
-  Boolean indicating whether the JasPer is found.  For backward compatibility,
-  the ``JASPER_FOUND`` variable is also set to the same value.
+  Boolean indicating whether (the requested version of) JasPer is found.
+  For backward compatibility, the ``JASPER_FOUND`` variable is also set to
+  the same value.
+
+``Jasper_VERSION``
+  .. versionadded:: 4.2
+
+  The version of JasPer found.
 
 ``JASPER_INCLUDE_DIRS``
   .. versionadded:: 3.22
@@ -36,9 +46,6 @@
 ``JASPER_LIBRARIES``
   The libraries needed to use JasPer.
 
-``JASPER_VERSION_STRING``
-  The version of JasPer found.
-
 Cache Variables
 ^^^^^^^^^^^^^^^
 
@@ -54,6 +61,17 @@
 ``JASPER_LIBRARY_DEBUG``
   The path to the debug variant of the JasPer library.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``JASPER_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``Jasper_VERSION``.
+
+  The version of JasPer found.
+
 Examples
 ^^^^^^^^
 
@@ -81,13 +99,14 @@
 
 if(JASPER_INCLUDE_DIR AND EXISTS "${JASPER_INCLUDE_DIR}/jasper/jas_config.h")
   file(STRINGS "${JASPER_INCLUDE_DIR}/jasper/jas_config.h" jasper_version_str REGEX "^#define[\t ]+JAS_VERSION[\t ]+\".*\".*")
-  string(REGEX REPLACE "^#define[\t ]+JAS_VERSION[\t ]+\"([^\"]+)\".*" "\\1" JASPER_VERSION_STRING "${jasper_version_str}")
+  string(REGEX REPLACE "^#define[\t ]+JAS_VERSION[\t ]+\"([^\"]+)\".*" "\\1" Jasper_VERSION "${jasper_version_str}")
+  set(JASPER_VERSION_STRING "${Jasper_VERSION}")
 endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Jasper
                                   REQUIRED_VARS JASPER_LIBRARIES JASPER_INCLUDE_DIR
-                                  VERSION_VAR JASPER_VERSION_STRING)
+                                  VERSION_VAR Jasper_VERSION)
 
 if(Jasper_FOUND)
   set(JASPER_LIBRARIES ${JASPER_LIBRARIES})
diff --git a/Modules/FindJava.cmake b/Modules/FindJava.cmake
index 1587ce6..acd624f 100644
--- a/Modules/FindJava.cmake
+++ b/Modules/FindJava.cmake
@@ -6,7 +6,11 @@
 --------
 
 Finds the Java installation and determines its runtime tools and development
-components.
+components:
+
+.. code-block:: cmake
+
+  find_package(Java [<version>] [COMPONENTS <components>...] [...])
 
 .. versionadded:: 3.10
   Support for Java 9+ version parsing.
@@ -14,7 +18,14 @@
 Components
 ^^^^^^^^^^
 
-This module supports the following components:
+This module supports optional components, which can be specified with the
+:command:`find_package` command:
+
+.. code-block:: cmake
+
+  find_package(Java [COMPONENTS <components>...])
+
+Supported components include:
 
 ``Runtime``
   Finds the Java Runtime Environment used to execute Java byte-compiled
@@ -35,13 +46,7 @@
 
   Finds the signer and verifier tool for Java Archive (JAR) files.
 
-Components can optionally be specified using the standard syntax with:
-
-.. code-block:: cmake
-
-  find_package(Java [COMPONENTS <components>...])
-
-If no ``COMPONENTS`` are specified, the module searches for the ``Runtime``
+If no components are specified, the module searches for the ``Runtime``
 component by default.
 
 Result Variables
diff --git a/Modules/FindKDE3.cmake b/Modules/FindKDE3.cmake
index ccfad5e..438c0b0 100644
--- a/Modules/FindKDE3.cmake
+++ b/Modules/FindKDE3.cmake
@@ -13,9 +13,15 @@
   `KDE documentation
   <https://develop.kde.org/docs/getting-started/building/cmake-build/>`_.
 
-This module finds KDE 3 include directories, libraries, and KDE-specific
-preprocessor tools.  It provides usage requirements for building KDE 3 software
-and defines several helper commands to simplify working with KDE 3 in CMake.
+Finds KDE 3 include directories, libraries, and KDE-specific preprocessor
+tools:
+
+.. code-block:: cmake
+
+  find_package(KDE3 [...])
+
+This module provides usage requirements for building KDE 3 software and
+defines several helper commands to simplify working with KDE 3 in CMake.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -206,7 +212,7 @@
 endif()
 
 # If Qt4 has already been found, fail.
-if(QT4_FOUND)
+if(Qt4_FOUND)
   if(KDE3_FIND_REQUIRED)
     message( FATAL_ERROR "KDE3/Qt3 and Qt4 cannot be used together in one project.")
   else()
diff --git a/Modules/FindLAPACK.cmake b/Modules/FindLAPACK.cmake
index af358c3..2522811 100644
--- a/Modules/FindLAPACK.cmake
+++ b/Modules/FindLAPACK.cmake
@@ -5,35 +5,68 @@
 FindLAPACK
 ----------
 
-Find Linear Algebra PACKage (LAPACK) library
+Finds the installed Linear Algebra PACKage (LAPACK) Fortran library that
+implements the `LAPACK linear-algebra interface`_:
 
-This module finds an installed Fortran library that implements the
-`LAPACK linear-algebra interface`_.
+.. code-block:: cmake
+
+  find_package(LAPACK [...])
 
 At least one of the ``C``, ``CXX``, or ``Fortran`` languages must be enabled.
 
 .. _`LAPACK linear-algebra interface`: https://netlib.org/lapack/
 
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module provides the following :ref:`Imported Targets`:
+
+``LAPACK::LAPACK``
+  .. versionadded:: 3.18
+
+  Target encapsulating the LAPACK usage requirements, available only if
+  LAPACK is found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``LAPACK_FOUND``
+  Boolean indicating whether the library implementing the LAPACK interface
+  is found.
+``LAPACK_LINKER_FLAGS``
+  Uncached list of required linker flags (excluding ``-l`` and ``-L``).
+``LAPACK_LIBRARIES``
+  Uncached list of libraries (using full path name) to link against to use
+  LAPACK.
+``LAPACK95_LIBRARIES``
+  Uncached list of libraries (using full path name) to link against to use
+  LAPACK95.
+``LAPACK95_FOUND``
+  Boolean indicating whether the library implementing the LAPACK95 interface
+  is found.
+
 Input Variables
 ^^^^^^^^^^^^^^^
 
 The following variables may be set to influence this module's behavior:
 
 ``BLA_STATIC``
-  if ``ON`` use static linkage
+  If ``ON``, the static linkage will be used.
 
 ``BLA_VENDOR``
   Set to one of the :ref:`BLAS/LAPACK Vendors` to search for BLAS only
   from the specified vendor.  If not set, all vendors are considered.
 
 ``BLA_F95``
-  if ``ON`` tries to find the BLAS95/LAPACK95 interfaces
+  If ``ON``, the module tries to find the BLAS95/LAPACK95 interfaces.
 
 ``BLA_PREFER_PKGCONFIG``
   .. versionadded:: 3.20
 
-  if set ``pkg-config`` will be used to search for a LAPACK library first
-  and if one is found that is preferred
+  If set, ``pkg-config`` will be used to search for a LAPACK library first
+  and if one is found that is preferred.
 
 ``BLA_PKGCONFIG_LAPACK``
   .. versionadded:: 3.25
@@ -41,7 +74,6 @@
   If set, the ``pkg-config`` method will look for this module name instead of
   just ``lapack``.
 
-
 ``BLA_SIZEOF_INTEGER``
   .. versionadded:: 3.22
 
@@ -70,34 +102,6 @@
 
   This is currently only supported by NVIDIA NVPL.
 
-Imported Targets
-^^^^^^^^^^^^^^^^
-
-This module defines the following :prop_tgt:`IMPORTED` targets:
-
-``LAPACK::LAPACK``
-  .. versionadded:: 3.18
-
-  The libraries to use for LAPACK, if found.
-
-Result Variables
-^^^^^^^^^^^^^^^^
-
-This module defines the following variables:
-
-``LAPACK_FOUND``
-  library implementing the LAPACK interface is found
-``LAPACK_LINKER_FLAGS``
-  uncached list of required linker flags (excluding ``-l`` and ``-L``).
-``LAPACK_LIBRARIES``
-  uncached list of libraries (using full path name) to link against
-  to use LAPACK
-``LAPACK95_LIBRARIES``
-  uncached list of libraries (using full path name) to link against
-  to use LAPACK95
-``LAPACK95_FOUND``
-  library implementing the LAPACK95 interface is found
-
 Intel MKL
 ^^^^^^^^^
 
@@ -115,6 +119,15 @@
 establish an Intel MKL environment.  See the :module:`FindBLAS` module
 section on :ref:`Intel MKL` for details.
 
+Examples
+^^^^^^^^
+
+Finding LAPACK and linking it to a project target:
+
+.. code-block:: cmake
+
+  find_package(LAPACK)
+  target_link_libraries(project_target PRIVATE LAPACK::LAPACK)
 #]=======================================================================]
 
 # The approach follows that of the ``autoconf`` macro file, ``acx_lapack.m4``
diff --git a/Modules/FindLATEX.cmake b/Modules/FindLATEX.cmake
index e272770..6138984 100644
--- a/Modules/FindLATEX.cmake
+++ b/Modules/FindLATEX.cmake
@@ -5,8 +5,14 @@
 FindLATEX
 ---------
 
-Finds LaTeX compiler and Latex-related software like BibTeX.  LaTeX is a
-typesetting system for the production of technical and scientific documentation.
+Finds LaTeX compiler and Latex-related software like BibTeX:
+
+.. code-block:: cmake
+
+  find_package(LATEX [...])
+
+LaTeX is a typesetting system for the production of technical and scientific
+documentation.
 
 Components
 ^^^^^^^^^^
@@ -40,7 +46,7 @@
   Finds the MakeIndex compiler.
 
 ``XINDY``
-  Find the xindy compiler.
+  Finds the xindy compiler.
 
 ``DVIPS``
   Finds the DVI-to-PostScript (DVIPS) converter.
diff --git a/Modules/FindLTTngUST.cmake b/Modules/FindLTTngUST.cmake
index 14aa766..6ca7b85 100644
--- a/Modules/FindLTTngUST.cmake
+++ b/Modules/FindLTTngUST.cmake
@@ -8,12 +8,16 @@
 .. versionadded:: 3.6
 
 Finds the `LTTng <https://lttng.org/>`_ (Linux Trace Toolkit: next generation)
-user space tracing library (LTTng-UST).
+user space tracing library (LTTng-UST):
+
+.. code-block:: cmake
+
+  find_package(LTTngUST [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets`:
+This module provides the following :ref:`Imported Targets`:
 
 ``LTTng::UST``
   Target providing the LTTng-UST library usage requirements.  This target is
@@ -22,15 +26,20 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``LTTngUST_FOUND``
   Boolean indicating whether the LTTng-UST library is found.  For backward
   compatibility, the ``LTTNGUST_FOUND`` variable is also set to the same value.
-``LTTNGUST_VERSION_STRING``
+
+``LTTngUST_VERSION``
+  .. versionadded:: 4.2
+
   The LTTng-UST version.
+
 ``LTTNGUST_HAS_TRACEF``
   ``TRUE`` if the ``tracef()`` API is available in the system's LTTng-UST.
+
 ``LTTNGUST_HAS_TRACELOG``
   ``TRUE`` if the ``tracelog()`` API is available in the system's LTTng-UST.
 
@@ -44,6 +53,17 @@
 ``LTTNGUST_LIBRARIES``
   The libraries needed to use LTTng-UST.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``LTTNGUST_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``LTTngUST_VERSION``.
+
+  The LTTng-UST version.
+
 Examples
 ^^^^^^^^
 
@@ -90,8 +110,9 @@
            lttngust_v_minor "${lttngust_version_minor_string}")
     string(REGEX REPLACE ".*[\t ]+([0-9]+).*" "\\1"
            lttngust_v_patch "${lttngust_version_patch_string}")
-    set(LTTNGUST_VERSION_STRING
+    set(LTTngUST_VERSION
         "${lttngust_v_major}.${lttngust_v_minor}.${lttngust_v_patch}")
+    set(LTTNGUST_VERSION_STRING "${LTTngUST_VERSION}")
     unset(lttngust_version_major_string)
     unset(lttngust_version_minor_string)
     unset(lttngust_version_patch_string)
@@ -119,7 +140,7 @@
 find_package_handle_standard_args(LTTngUST
                                   REQUIRED_VARS LTTNGUST_LIBRARIES
                                                 LTTNGUST_INCLUDE_DIRS
-                                  VERSION_VAR LTTNGUST_VERSION_STRING)
+                                  VERSION_VAR LTTngUST_VERSION)
 mark_as_advanced(LTTNGUST_LIBRARIES LTTNGUST_INCLUDE_DIRS)
 
 cmake_policy(POP)
diff --git a/Modules/FindLibArchive.cmake b/Modules/FindLibArchive.cmake
index 9072d95..5f006e6 100644
--- a/Modules/FindLibArchive.cmake
+++ b/Modules/FindLibArchive.cmake
@@ -5,18 +5,24 @@
 FindLibArchive
 --------------
 
-Finds the libarchive library and include directories.  Libarchive is a
-multi-format archive and compression library.
+Finds the libarchive library and include directories:
 
-Import Targets
-^^^^^^^^^^^^^^
+.. code-block:: cmake
 
-This module defines the following :ref:`Imported Targets`:
+  find_package(LibArchive [<version>] [...])
+
+Libarchive is a multi-format archive and compression library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module provides the following :ref:`Imported Targets`:
 
 ``LibArchive::LibArchive``
   .. versionadded:: 3.17
 
-  A target for linking against libarchive.
+  A target encapsulating the libarchive usage requirements, available only
+  if libarchive is found.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -24,11 +30,8 @@
 This module defines the following variables:
 
 ``LibArchive_FOUND``
-  Boolean indicating whether libarchive was found.
-``LibArchive_INCLUDE_DIRS``
-  Include search path for using libarchive.
-``LibArchive_LIBRARIES``
-  Libraries to link against libarchive.
+  Boolean indicating whether (the requested version of) libarchive was found.
+
 ``LibArchive_VERSION``
   A 3-component version string (``major.minor.patch``) of libarchive found.
 
@@ -40,10 +43,16 @@
     only for libarchive versions 3.1 and earlier.  In CMake 3.6 and newer, this
     variable will be set for all libarchive versions.
 
+``LibArchive_INCLUDE_DIRS``
+  Include search path for using libarchive.
+
+``LibArchive_LIBRARIES``
+  Libraries to link against libarchive.
+
 Examples
 ^^^^^^^^
 
-Finding LibArchive and linking it to a project target:
+Finding libarchive and linking it to a project target:
 
 .. code-block:: cmake
 
diff --git a/Modules/FindLibLZMA.cmake b/Modules/FindLibLZMA.cmake
index 3711214..38ff888 100644
--- a/Modules/FindLibLZMA.cmake
+++ b/Modules/FindLibLZMA.cmake
@@ -5,8 +5,12 @@
 FindLibLZMA
 -----------
 
-Finds the data compression library that implements the LZMA (Lempel–Ziv–Markov
-chain algorithm) - liblzma.
+Finds the liblzma, a data compression library that implements the LZMA
+(Lempel–Ziv–Markov chain algorithm):
+
+.. code-block:: cmake
+
+  find_package(LibLZMA [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -25,17 +29,21 @@
 This module defines the following variables:
 
 ``LibLZMA_FOUND``
-  Boolean indicating whether the liblzma is found.  For backward compatibility,
-  the ``LIBLZMA_FOUND`` variable is also set to the same value.
-``LIBLZMA_INCLUDE_DIRS``
-  Include directories containing headers needed to use liblzma.
-``LIBLZMA_LIBRARIES``
-  Libraries needed to link against to use liblzma.
-``LIBLZMA_VERSION``
-  .. versionadded:: 3.26
+  Boolean indicating whether (the requested version of) liblzma is found.
+  For backward compatibility, the ``LIBLZMA_FOUND`` variable is also set to
+  the same value.
+
+``LibLZMA_VERSION``
+  .. versionadded:: 4.2
 
   The version of liblzma found (available as a string, for example, ``5.0.3``).
 
+``LIBLZMA_INCLUDE_DIRS``
+  Include directories containing headers needed to use liblzma.
+
+``LIBLZMA_LIBRARIES``
+  Libraries needed to link against to use liblzma.
+
 Cache Variables
 ^^^^^^^^^^^^^^^
 
@@ -44,29 +52,47 @@
 ``LIBLZMA_HAS_AUTO_DECODER``
   Boolean sanity check result indicating whether the ``lzma_auto_decoder()``
   function (automatic decoder functionality) is found in liblzma (required).
+
 ``LIBLZMA_HAS_EASY_ENCODER``
   Boolean sanity check result indicating whether the ``lzma_easy_encoder()``
   function (basic encoder API) is found in liblzma (required).
+
 ``LIBLZMA_HAS_LZMA_PRESET``
   Boolean sanity check result indicating whether the ``lzma_lzma_preset()``
   function (preset compression configuration) is found in liblzma (required).
 
-Legacy Variables
-^^^^^^^^^^^^^^^^
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
 
 The following variables are provided for backward compatibility:
 
-``LIBLZMA_VERSION_MAJOR``
-  The major version of liblzma found.
-``LIBLZMA_VERSION_MINOR``
-  The minor version of liblzma found.
-``LIBLZMA_VERSION_PATCH``
-  The patch version of liblzma found.
-``LIBLZMA_VERSION_STRING``
+``LIBLZMA_VERSION``
+  .. versionadded:: 3.26
+  .. deprecated:: 4.2
+    Superseded by the ``LibLZMA_VERSION``.
+
   The version of liblzma found.
 
-  .. versionchanged:: 3.26
-    Superseded by ``LIBLZMA_VERSION``.
+``LIBLZMA_VERSION_STRING``
+  .. deprecated:: 3.26
+    Superseded by the ``LIBLZMA_VERSION`` (and ``LibLZMA_VERSION``).
+
+  The version of liblzma found.
+
+``LIBLZMA_VERSION_MAJOR``
+  .. deprecated:: 3.26
+
+  The major version of liblzma found.
+
+``LIBLZMA_VERSION_MINOR``
+  .. deprecated:: 3.26
+
+  The minor version of liblzma found.
+
+``LIBLZMA_VERSION_PATCH``
+  .. deprecated:: 3.26
+
+  The patch version of liblzma found.
 
 Examples
 ^^^^^^^^
@@ -99,8 +125,9 @@
     string(REGEX REPLACE ".*#define LZMA_VERSION_MINOR ([0-9]+).*" "\\1" LIBLZMA_VERSION_MINOR "${LIBLZMA_HEADER_CONTENTS}")
     string(REGEX REPLACE ".*#define LZMA_VERSION_PATCH ([0-9]+).*" "\\1" LIBLZMA_VERSION_PATCH "${LIBLZMA_HEADER_CONTENTS}")
 
-    set(LIBLZMA_VERSION_STRING "${LIBLZMA_VERSION_MAJOR}.${LIBLZMA_VERSION_MINOR}.${LIBLZMA_VERSION_PATCH}")
-    set(LIBLZMA_VERSION ${LIBLZMA_VERSION_STRING})
+    set(LibLZMA_VERSION "${LIBLZMA_VERSION_MAJOR}.${LIBLZMA_VERSION_MINOR}.${LIBLZMA_VERSION_PATCH}")
+    set(LIBLZMA_VERSION "${LibLZMA_VERSION}")
+    set(LIBLZMA_VERSION_STRING "${LibLZMA_VERSION}")
     unset(LIBLZMA_HEADER_CONTENTS)
 endif()
 
@@ -131,7 +158,7 @@
                                                           LIBLZMA_HAS_AUTO_DECODER
                                                           LIBLZMA_HAS_EASY_ENCODER
                                                           LIBLZMA_HAS_LZMA_PRESET
-                                           VERSION_VAR    LIBLZMA_VERSION
+                                           VERSION_VAR    LibLZMA_VERSION
                                  )
 mark_as_advanced( LIBLZMA_INCLUDE_DIR LIBLZMA_LIBRARY )
 
diff --git a/Modules/FindLibXml2.cmake b/Modules/FindLibXml2.cmake
index f453021..844ec70 100644
--- a/Modules/FindLibXml2.cmake
+++ b/Modules/FindLibXml2.cmake
@@ -5,7 +5,11 @@
 FindLibXml2
 -----------
 
-Finds the XML processing library (libxml2).
+Finds the XML processing library (libxml2):
+
+.. code-block:: cmake
+
+  find_package(LibXml2 [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -30,15 +34,22 @@
 This module defines the following variables:
 
 ``LibXml2_FOUND``
-  Boolean indicating whether the libxml2 library is found.
+  Boolean indicating whether (the requested version of) libxml2 library is
+  found.
+
+``LibXml2_VERSION``
+  .. versionadded:: 4.2
+
+  The version of the libxml2 found.
+
 ``LIBXML2_INCLUDE_DIRS``
   Include directories needed to use the libxml2 library.
+
 ``LIBXML2_LIBRARIES``
   Libraries needed to link against to use the libxml2 library.
+
 ``LIBXML2_DEFINITIONS``
   The compiler switches required for using libxml2.
-``LIBXML2_VERSION_STRING``
-  The version of the libxml2 found.
 
 Cache Variables
 ^^^^^^^^^^^^^^^
@@ -47,11 +58,24 @@
 
 ``LIBXML2_INCLUDE_DIR``
   The include directory containing libxml2 headers.
+
 ``LIBXML2_LIBRARY``
   The path to the libxml2 library.
+
 ``LIBXML2_XMLLINT_EXECUTABLE``
   The path to the XML checking tool ``xmllint`` coming with libxml2.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``LIBXML2_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``LibXml2_VERSION``.
+
+  The version of the libxml2 found.
+
 Examples
 ^^^^^^^^
 
@@ -102,7 +126,8 @@
          REGEX "^#define[\t ]+LIBXML_DOTTED_VERSION[\t ]+\".*\"")
 
     string(REGEX REPLACE "^#define[\t ]+LIBXML_DOTTED_VERSION[\t ]+\"([^\"]*)\".*" "\\1"
-           LIBXML2_VERSION_STRING "${libxml2_version_str}")
+           LibXml2_VERSION "${libxml2_version_str}")
+    set(LIBXML2_VERSION_STRING "${LibXml2_VERSION}")
     unset(libxml2_version_str)
 endif()
 
@@ -123,7 +148,7 @@
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(LibXml2
                                   REQUIRED_VARS LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR
-                                  VERSION_VAR LIBXML2_VERSION_STRING)
+                                  VERSION_VAR LibXml2_VERSION)
 
 mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARY LIBXML2_XMLLINT_EXECUTABLE)
 
diff --git a/Modules/FindLibXslt.cmake b/Modules/FindLibXslt.cmake
index d612c7d..d77ca14 100644
--- a/Modules/FindLibXslt.cmake
+++ b/Modules/FindLibXslt.cmake
@@ -6,7 +6,11 @@
 -----------
 
 Finds the XSL Transformations, Extensible Stylesheet Language Transformations
-(XSLT) library (libxslt).
+(XSLT) library (libxslt):
+
+.. code-block:: cmake
+
+  find_package(LibXslt [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -33,11 +37,17 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``LibXslt_FOUND``
-  Boolean indicating whether the libxslt is found.  For backward compatibility,
-  the ``LIBXSLT_FOUND`` variable is also set to the same value.
+  Boolean indicating whether (the requested version of) libxslt is found.
+  For backward compatibility, the ``LIBXSLT_FOUND`` variable is also set to
+  the same value.
+
+``LibXslt_VERSION``
+  .. versionadded:: 4.2
+
+  The version of libxslt found.
 
 ``LIBXSLT_LIBRARIES``
   Libraries needed to link to libxslt.
@@ -45,9 +55,6 @@
 ``LIBXSLT_DEFINITIONS``
   Compiler switches required for using libxslt.
 
-``LIBXSLT_VERSION_STRING``
-  Version of libxslt found.
-
 ``LIBXSLT_EXSLT_LIBRARIES``
   Libraries needed when linking against the exslt library.  These are available
   and needed only when using exslt library.
@@ -70,6 +77,17 @@
   Full path to the XSLT processor executable ``xsltproc`` if found.  This path
   is optional.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``LIBXSLT_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``LibXslt_VERSION``.
+
+  The version of libxslt found.
+
 Examples
 ^^^^^^^^
 
@@ -159,20 +177,22 @@
 find_program(LIBXSLT_XSLTPROC_EXECUTABLE xsltproc)
 
 if(PC_LIBXSLT_VERSION)
-    set(LIBXSLT_VERSION_STRING ${PC_LIBXSLT_VERSION})
+    set(LibXslt_VERSION ${PC_LIBXSLT_VERSION})
+    set(LIBXSLT_VERSION_STRING "${LibXslt_VERSION}")
 elseif(LIBXSLT_INCLUDE_DIR AND EXISTS "${LIBXSLT_INCLUDE_DIR}/libxslt/xsltconfig.h")
     file(STRINGS "${LIBXSLT_INCLUDE_DIR}/libxslt/xsltconfig.h" libxslt_version_str
          REGEX "^#define[\t ]+LIBXSLT_DOTTED_VERSION[\t ]+\".*\"")
 
     string(REGEX REPLACE "^#define[\t ]+LIBXSLT_DOTTED_VERSION[\t ]+\"([^\"]*)\".*" "\\1"
-           LIBXSLT_VERSION_STRING "${libxslt_version_str}")
+           LibXslt_VERSION "${libxslt_version_str}")
+    set(LIBXSLT_VERSION_STRING "${LibXslt_VERSION}")
     unset(libxslt_version_str)
 endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(LibXslt
                                   REQUIRED_VARS LIBXSLT_LIBRARIES LIBXSLT_INCLUDE_DIR
-                                  VERSION_VAR LIBXSLT_VERSION_STRING)
+                                  VERSION_VAR LibXslt_VERSION)
 
 mark_as_advanced(LIBXSLT_INCLUDE_DIR
                  LIBXSLT_LIBRARY
diff --git a/Modules/FindLibinput.cmake b/Modules/FindLibinput.cmake
index f3e66af..ca2c2a0 100644
--- a/Modules/FindLibinput.cmake
+++ b/Modules/FindLibinput.cmake
@@ -8,7 +8,11 @@
 .. versionadded:: 3.14
 
 Finds the libinput library which handles input devices in Wayland compositors
-and provides a generic X.Org input driver.
+and provides a generic X.Org input driver:
+
+.. code-block:: cmake
+
+  find_package(Libinput [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
diff --git a/Modules/FindMFC.cmake b/Modules/FindMFC.cmake
index 27c5458..70f73fb 100644
--- a/Modules/FindMFC.cmake
+++ b/Modules/FindMFC.cmake
@@ -6,7 +6,11 @@
 -------
 
 Finds the native Microsoft Foundation Class Library (MFC) for developing MFC
-applications on Windows.
+applications on Windows:
+
+.. code-block:: cmake
+
+  find_package(MFC [...])
 
 .. note::
 
diff --git a/Modules/FindMPEG.cmake b/Modules/FindMPEG.cmake
index 6c49702..a84c9b4 100644
--- a/Modules/FindMPEG.cmake
+++ b/Modules/FindMPEG.cmake
@@ -5,7 +5,11 @@
 FindMPEG
 --------
 
-Finds the native MPEG library (libmpeg2).
+Finds the native MPEG library (libmpeg2):
+
+.. code-block:: cmake
+
+  find_package(MPEG [...])
 
 .. note::
 
@@ -31,7 +35,7 @@
 Cache Variables
 ^^^^^^^^^^^^^^^
 
-The following cache variables may be also set:
+The following cache variables may also be set:
 
 ``MPEG_INCLUDE_DIR``
   The directory containing the ``mpeg2.h`` and related headers needed to use
diff --git a/Modules/FindMPEG2.cmake b/Modules/FindMPEG2.cmake
index 103f2c4..9ffd0df 100644
--- a/Modules/FindMPEG2.cmake
+++ b/Modules/FindMPEG2.cmake
@@ -5,7 +5,11 @@
 FindMPEG2
 ---------
 
-Finds the native MPEG2 library (libmpeg2).
+Finds the native MPEG2 library (libmpeg2):
+
+.. code-block:: cmake
+
+  find_package(MPEG2 [...])
 
 .. note::
 
@@ -26,7 +30,7 @@
 Cache Variables
 ^^^^^^^^^^^^^^^
 
-The following cache variables may be also set:
+The following cache variables may also be set:
 
 ``MPEG2_INCLUDE_DIR``
   The directory containing the ``mpeg2.h`` and related headers needed to use
diff --git a/Modules/FindMotif.cmake b/Modules/FindMotif.cmake
index d72b193..e68ed73 100644
--- a/Modules/FindMotif.cmake
+++ b/Modules/FindMotif.cmake
@@ -5,7 +5,11 @@
 FindMotif
 ---------
 
-Finds Motif (or LessTif) graphical user interface toolkit.
+Finds Motif (or LessTif) graphical user interface toolkit:
+
+.. code-block:: cmake
+
+  find_package(Motif [...])
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -21,19 +25,33 @@
 
 The following cache variables may also be set:
 
-``MOTIF_LIBRARIES``
-  Libraries needed to link to Motif.
 ``MOTIF_INCLUDE_DIR``
   Include directories needed to use Motif.
 
+``MOTIF_LIBRARIES``
+  Libraries needed to link to Motif.
+
 Examples
 ^^^^^^^^
 
-Finding Motif:
+Finding Motif and creating an imported interface target for linking it to a
+project target:
 
 .. code-block:: cmake
 
   find_package(Motif)
+
+  if(Motif_FOUND AND NOT TARGET Motif::Motif)
+    add_library(Motif::Motif INTERFACE IMPORTED)
+    set_target_properties(
+      Motif::Motif
+      PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${MOTIF_INCLUDE_DIR}"
+        INTERFACE_LINK_LIBRARIES "${MOTIF_LIBRARIES}"
+    )
+  endif()
+
+  target_link_libraries(example PRIVATE Motif::Motif)
 #]=======================================================================]
 
 if(UNIX)
diff --git a/Modules/FindMsys.cmake b/Modules/FindMsys.cmake
index 0d78c9b..4265798 100644
--- a/Modules/FindMsys.cmake
+++ b/Modules/FindMsys.cmake
@@ -8,7 +8,11 @@
 .. versionadded:: 3.21
 
 Finds MSYS, a POSIX-compatible environment that runs natively on Microsoft
-Windows.
+Windows:
+
+.. code-block:: cmake
+
+  find_package(Msys [...])
 
 .. note::
 
@@ -32,7 +36,7 @@
 Finding the MSYS installation and using its path in a custom find module:
 
 .. code-block:: cmake
-  :caption: FindFoo.cmake
+  :caption: ``FindFoo.cmake``
 
   find_package(Msys)
   find_program(Foo_EXECUTABLE NAMES foo PATHS ${MSYS_INSTALL_PATH}/usr/bin)
diff --git a/Modules/FindODBC.cmake b/Modules/FindODBC.cmake
index 6e103d2..bcb9cd3 100644
--- a/Modules/FindODBC.cmake
+++ b/Modules/FindODBC.cmake
@@ -7,11 +7,16 @@
 
 .. versionadded:: 3.12
 
-Finds the Open Database Connectivity (ODBC) library, which implements a standard
-API for accessing database systems.  ODBC enables applications to communicate
-with different database management systems (DBMS) using a common set of
-functions.  Communication with a specific database is handled through ODBC
-drivers, which the library loads at runtime.
+Finds the Open Database Connectivity (ODBC) library, which implements a
+standard API for accessing database systems:
+
+.. code-block:: cmake
+
+  find_package(ODBC [...])
+
+ODBC enables applications to communicate with different database management
+systems (DBMS) using a common set of functions.  Communication with a specific
+database is handled through ODBC drivers, which the library loads at runtime.
 
 On Windows, when building with Visual Studio, this module assumes the ODBC
 library is provided by the available Windows SDK.
@@ -76,19 +81,19 @@
 Examples
 ^^^^^^^^
 
-Finding and using ODBC
-""""""""""""""""""""""
+Example: Finding and Using ODBC
+"""""""""""""""""""""""""""""""
 
 Finding ODBC and linking it to a project target:
 
 .. code-block:: cmake
-  :caption: CMakeLists.txt
+  :caption: ``CMakeLists.txt``
 
   find_package(ODBC)
   target_link_libraries(project_target PRIVATE ODBC::ODBC)
 
-Finding a custom ODBC installation on Unix-like systems
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Example: Finding a Custom ODBC Installation
+"""""""""""""""""""""""""""""""""""""""""""
 
 The following examples are for Unix-like systems and demonstrate how to set hint
 and cache variables during the CMake configuration phase to help this module
diff --git a/Modules/FindOpenACC.cmake b/Modules/FindOpenACC.cmake
index b78d381..84c7bf0 100644
--- a/Modules/FindOpenACC.cmake
+++ b/Modules/FindOpenACC.cmake
@@ -7,9 +7,12 @@
 
 .. versionadded:: 3.10
 
-Detect OpenACC support by the compiler.
+Finds and detects the OpenACC support in a compiler:
 
-This module can be used to detect OpenACC support in a compiler.
+.. code-block:: cmake
+
+  find_package(OpenACC [<version>] [...])
+
 If the compiler supports OpenACC, the flags required to compile with
 OpenACC support are returned in variables for the different languages.
 Currently, only NVHPC, PGI, GNU and Cray compilers are supported.
@@ -17,28 +20,31 @@
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.16
-
-The module provides :prop_tgt:`IMPORTED` targets:
+This module provides the following :ref:`Imported Targets`:
 
 ``OpenACC::OpenACC_<lang>``
-  Target for using OpenACC from ``<lang>``.
+  .. versionadded:: 3.16
 
-Variables
-^^^^^^^^^
+  Target encapsulating the usage requirements for using OpenACC from
+  ``<lang>``.  This target is available only if OpenACC support is found.
+  ``<lang>`` is one of C, CXX, or Fortran.
 
-The module defines the following variables:
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
 
 ``OpenACC_FOUND``
   .. versionadded:: 3.25
 
-  Variable indicating that OpenACC flags for at least one languages have been found.
+  Boolean variable indicating that OpenACC flags for at least one languages
+  have been found.
 
-This module will set the following variables per language in your
+This module will set the following variables per language in the
 project, where ``<lang>`` is one of C, CXX, or Fortran:
 
 ``OpenACC_<lang>_FOUND``
-  Variable indicating if OpenACC support for ``<lang>`` was detected.
+  Boolean variable indicating if OpenACC support for ``<lang>`` was detected.
 ``OpenACC_<lang>_FLAGS``
   OpenACC compiler flags for ``<lang>``, separated by spaces.
 ``OpenACC_<lang>_OPTIONS``
@@ -65,9 +71,21 @@
 Input Variables
 ^^^^^^^^^^^^^^^
 
+This module accepts the following variables:
+
 ``OpenACC_ACCEL_TARGET=<target>``
-If set, will the correct target accelerator flag set to the <target> will
-be returned with OpenACC_<lang>_FLAGS.
+  If set, the correct target accelerator flag set to the ``<target>``
+  will be returned with the ``OpenACC_<lang>_FLAGS`` variable.
+
+Examples
+^^^^^^^^
+
+Finding OpenACC support and linking the imported target to a project target:
+
+.. code-block:: cmake
+
+  find_package(OpenACC)
+  target_link_libraries(example PRIVATE OpenACC::OpenACC_C)
 #]=======================================================================]
 
 cmake_policy(PUSH)
diff --git a/Modules/FindOpenGL.cmake b/Modules/FindOpenGL.cmake
index a842756..b32bbcc 100644
--- a/Modules/FindOpenGL.cmake
+++ b/Modules/FindOpenGL.cmake
@@ -5,28 +5,56 @@
 FindOpenGL
 ----------
 
-FindModule for OpenGL and OpenGL Utility Library (GLU).
+Finds the OpenGL and OpenGL Utility Library (GLU), for using OpenGL in a
+CMake project:
+
+.. code-block:: cmake
+
+  find_package(OpenGL [COMPONENTS <components>...] [...])
+
+OpenGL (Open Graphics Library) is a cross-platform API for rendering 2D and
+3D graphics.  It is widely used in CAD, games, and visualization software.
+
+* *GL* refers to the core OpenGL library, which provides the fundamental
+  graphics rendering API.
+
+* *GLU* (OpenGL Utility Library) is a companion library that offers utility
+  functions built on top of OpenGL, such as tessellation and more complex
+  shape drawing.
 
 .. versionchanged:: 3.2
   X11 is no longer added as a dependency on Unix/Linux systems.
 
 .. versionadded:: 3.10
-  GLVND support on Linux.  See the :ref:`Linux Specific` section below.
+  GLVND (GL Vendor-Neutral Dispatch library) support on Linux.  See the
+  :ref:`Linux Specific` section below.
 
-Optional COMPONENTS
-^^^^^^^^^^^^^^^^^^^
+Components
+^^^^^^^^^^
 
-.. versionadded:: 3.10
+This module supports optional components which can be specified with the
+:command:`find_package` command:
 
-This module respects several optional COMPONENTS:
+.. code-block:: cmake
+
+  find_package(OpenGL [COMPONENTS <components>...])
+
+Supported components are:
 
 ``EGL``
-  The EGL interface between OpenGL, OpenGL ES and the underlying windowing system.
+  .. versionadded:: 3.10
+
+  The EGL interface between OpenGL, OpenGL ES and the underlying windowing
+  system.
 
 ``GLX``
+  .. versionadded:: 3.10
+
   An extension to X that interfaces OpenGL, OpenGL ES with X window system.
 
 ``OpenGL``
+  .. versionadded:: 3.10
+
   The cross platform API for 3D graphics.
 
 ``GLES2``
@@ -42,103 +70,177 @@
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.8
-
-This module defines the :prop_tgt:`IMPORTED` targets:
+This module provides the following :ref:`Imported Targets`:
 
 ``OpenGL::GL``
-  Defined to the platform-specific OpenGL libraries if the system has OpenGL.
-``OpenGL::GLU``
-  Defined if the system has OpenGL Utility Library (GLU).
+  .. versionadded:: 3.8
 
-.. versionadded:: 3.10
-  Additionally, the following GLVND-specific library targets are defined:
+  Target encapsulating the usage requirements of platform-specific OpenGL
+  libraries, available if OpenGL is found.
+
+``OpenGL::GLU``
+  .. versionadded:: 3.8
+
+  Target encapsulating the OpenGL Utility Library (GLU) usage requirements,
+  available if GLU is found.
+
+Additionally, the following GLVND-specific library imported targets are
+provided:
 
 ``OpenGL::OpenGL``
-  Defined to libOpenGL if the system is GLVND-based.
+  .. versionadded:: 3.10
+
+  Target encapsulating the libOpenGL usage requirements, available if
+  system is GLVND-based and OpenGL is found.
+
 ``OpenGL::GLX``
-  Defined if the system has OpenGL Extension to the X Window System (GLX).
+  .. versionadded:: 3.10
+
+  Target encapsulating the usage requirements of the OpenGL Extension to the
+  the X Window System (GLX), available if OpenGL and GLX are found.
+
 ``OpenGL::EGL``
-  Defined if the system has EGL.
+  .. versionadded:: 3.10
+
+  Target encapsulating the EGL usage requirements, available if OpenGL and EGL
+  are found.
+
 ``OpenGL::GLES2``
   .. versionadded:: 3.27
 
-  Defined if the system has GLES2.
+  Target encapsulating the GLES2 usage requirements, available if OpenGL and
+  GLES2 are found.
+
 ``OpenGL::GLES3``
   .. versionadded:: 3.27
 
-  Defined if the system has GLES3.
+  Target encapsulating the GLES3 usage requirements, available if OpenGL and
+  GLES3 are found.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
-``OPENGL_FOUND``
- True, if the system has OpenGL and all components are found.
+``OpenGL_FOUND``
+  .. versionadded:: 3.3
+
+  Boolean indicating whether the OpenGL and all requested components are found.
+
 ``OPENGL_XMESA_FOUND``
- True, if the system has XMESA.
+  Boolean indicating whether OpenGL XMESA is found.
+
 ``OPENGL_GLU_FOUND``
- True, if the system has GLU.
+  Boolean indicating whether GLU is found.
+
 ``OpenGL_OpenGL_FOUND``
- True, if the system has an OpenGL library.
+  .. versionadded:: 3.10
+
+  Boolean indicating whether GLVND OpenGL library is found.
+
 ``OpenGL_GLX_FOUND``
- True, if the system has GLX.
+  .. versionadded:: 3.10
+
+  Boolean indicating whether GLVND GLX is found.
+
 ``OpenGL_EGL_FOUND``
- True, if the system has EGL.
-``OpenGL::GLES2``
- Defined if the system has GLES2.
-``OpenGL::GLES3``
- Defined if the system has GLES3.
-``OPENGL_INCLUDE_DIR``
- Path to the OpenGL include directory.
- The ``OPENGL_INCLUDE_DIRS`` variable is preferred.
-``OPENGL_EGL_INCLUDE_DIRS``
- Path to the EGL include directory.
-``OPENGL_LIBRARIES``
- Paths to the OpenGL library, windowing system libraries, and GLU libraries.
- On Linux, this assumes GLX and is never correct for EGL-based targets.
- Clients are encouraged to use the ``OpenGL::*`` import targets instead.
+  .. versionadded:: 3.10
+
+  Boolean indicating whether GLVND EGL is found.
+
+``OpenGL_GLES2_FOUND``
+  .. versionadded:: 3.27
+
+  Boolean indicating whether GLES2 is found.
+
+``OpenGL_GLES3_FOUND``
+  .. versionadded:: 3.27
+
+  Boolean indicating whether GLES3 is found.
+
 ``OPENGL_INCLUDE_DIRS``
   .. versionadded:: 3.29
 
   Paths to the OpenGL include directories.
 
-.. versionadded:: 3.10
-  Variables for GLVND-specific libraries ``OpenGL``, ``EGL`` and ``GLX``.
+``OPENGL_EGL_INCLUDE_DIRS``
+  .. versionadded:: 3.10
 
-Cache variables
+  Path to the EGL include directory.
+
+``OPENGL_LIBRARIES``
+  Paths to the OpenGL library, windowing system libraries, and GLU libraries.
+  On Linux, this assumes GLX and is never correct for EGL-based targets.
+  Clients are encouraged to use the ``OpenGL::*`` imported targets instead.
+
+Cache Variables
 ^^^^^^^^^^^^^^^
 
 The following cache variables may also be set:
 
-``OPENGL_egl_LIBRARY``
- Path to the EGL library.
-``OPENGL_glu_LIBRARY``
- Path to the GLU library.
-``OPENGL_glx_LIBRARY``
- Path to the GLVND 'GLX' library.
-``OPENGL_opengl_LIBRARY``
- Path to the GLVND 'OpenGL' library
-``OPENGL_gl_LIBRARY``
- Path to the OpenGL library.  New code should prefer the ``OpenGL::*`` import
- targets.
-``OPENGL_gles2_LIBRARY``
-  .. versionadded:: 3.27
-
-  Path to the OpenGL GLES2 library.
-``OPENGL_gles3_LIBRARY``
-  .. versionadded:: 3.27
-
-  Path to the OpenGL GLES3 library.
+``OPENGL_INCLUDE_DIR``
+  The path to the OpenGL include directory.
+  The ``OPENGL_INCLUDE_DIRS`` variable is preferred.
 
 ``OPENGL_GLU_INCLUDE_DIR``
   .. versionadded:: 3.29
 
   Path to the OpenGL GLU include directory.
 
-.. versionadded:: 3.10
-  Variables for GLVND-specific libraries ``OpenGL``, ``EGL`` and ``GLX``.
+``OPENGL_egl_LIBRARY``
+  .. versionadded:: 3.10
+
+  Path to the GLVND EGL library.
+
+``OPENGL_glu_LIBRARY``
+  Path to the GLU library.
+
+``OPENGL_glx_LIBRARY``
+  .. versionadded:: 3.10
+
+  Path to the GLVND GLX library.
+
+``OPENGL_opengl_LIBRARY``
+  .. versionadded:: 3.10
+
+  Path to the GLVND OpenGL library
+
+``OPENGL_gl_LIBRARY``
+  Path to the OpenGL library.
+
+``OPENGL_gles2_LIBRARY``
+  .. versionadded:: 3.27
+
+  Path to the OpenGL GLES2 library.
+
+``OPENGL_gles3_LIBRARY``
+  .. versionadded:: 3.27
+
+  Path to the OpenGL GLES3 library.
+
+Hints
+^^^^^
+
+This module accepts the following variables:
+
+``OpenGL_GL_PREFERENCE``
+  .. versionadded:: 3.10
+
+  This variable is supported on Linux systems to specify the preferred way to
+  provide legacy GL interfaces in case multiple choices are available.  The
+  value may be one of:
+
+  ``GLVND``
+    If the GLVND OpenGL and GLX libraries are available, prefer them.
+    This forces ``OPENGL_gl_LIBRARY`` to be empty.
+
+    .. versionchanged:: 3.11
+      This is the default, unless policy :policy:`CMP0072` is set to ``OLD``
+      and no components are requested (since components
+      correspond to GLVND libraries).
+
+  ``LEGACY``
+    Prefer to use the legacy libGL library, if available.
 
 .. _`Linux Specific`:
 
@@ -160,21 +262,8 @@
 variable will use the corresponding libraries).  Thus, for non-EGL-based
 Linux targets, the ``OpenGL::GL`` target is most portable.
 
-A ``OpenGL_GL_PREFERENCE`` variable may be set to specify the preferred way
+The ``OpenGL_GL_PREFERENCE`` variable may be set to specify the preferred way
 to provide legacy GL interfaces in case multiple choices are available.
-The value may be one of:
-
-``GLVND``
- If the GLVND OpenGL and GLX libraries are available, prefer them.
- This forces ``OPENGL_gl_LIBRARY`` to be empty.
-
- .. versionchanged:: 3.11
-  This is the default, unless policy :policy:`CMP0072` is set to ``OLD``
-  and no components are requested (since components
-  correspond to GLVND libraries).
-
-``LEGACY``
- Prefer to use the legacy libGL library, if available.
 
 For EGL targets the client must rely on GLVND support on the user's system.
 Linking should use the ``OpenGL::OpenGL OpenGL::EGL`` targets.  Using GLES*
@@ -189,7 +278,8 @@
 
 On macOS this module defaults to using the macOS-native framework
 version of OpenGL.  To use the X11 version of OpenGL on macOS, one
-can disable searching of frameworks.  For example:
+can disable searching of frameworks using the :variable:`CMAKE_FIND_FRAMEWORK`
+variable.  For example:
 
 .. code-block:: cmake
 
@@ -205,6 +295,33 @@
 An end user building this project may need to point CMake at their
 X11 installation, e.g., with ``-DOpenGL_ROOT=/opt/X11``.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``OPENGL_FOUND``
+  .. deprecated:: 3.3
+    Superseded by the ``OpenGL_FOUND``, which has the same value.
+
+Examples
+^^^^^^^^
+
+Finding the OpenGL library and linking it to a project target:
+
+.. code-block:: cmake
+
+  find_package(OpenGL)
+  target_link_libraries(project_target PRIVATE OpenGL::OpenGL)
+
+See Also
+^^^^^^^^
+
+* The :module:`FindGLEW` module to find OpenGL Extension Wrangler Library
+  (GLEW).
+* The :module:`FindGLUT` module to find OpenGL Utility Toolkit (GLUT)
+  library.
+* The :module:`FindVulkan` module to find Vulkan graphics API.
 #]=======================================================================]
 
 set(_OpenGL_REQUIRED_VARS OPENGL_gl_LIBRARY)
@@ -582,7 +699,7 @@
 unset(_OpenGL_REQUIRED_VARS)
 
 # OpenGL:: targets
-if(OPENGL_FOUND)
+if(OpenGL_FOUND)
   set(OPENGL_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR})
 
   # ::OpenGL is a GLVND library, and thus Linux-only: we don't bother checking
diff --git a/Modules/FindOpenMP.cmake b/Modules/FindOpenMP.cmake
index c1141c7..30802d6 100644
--- a/Modules/FindOpenMP.cmake
+++ b/Modules/FindOpenMP.cmake
@@ -5,17 +5,59 @@
 FindOpenMP
 ----------
 
-Finds Open Multi-Processing (OpenMP) support.
+Finds Open Multi-Processing (OpenMP) support in a compiler:
 
-This module can be used to detect OpenMP support in a compiler.  If
-the compiler supports OpenMP, the flags required to compile with
-OpenMP support are returned in variables for the different languages.
-The variables may be empty if the compiler does not need a special
-flag to support OpenMP.
+.. code-block:: cmake
+
+  find_package(OpenMP [<version>] [COMPONENTS <components>...] [...])
+
+If the compiler supports OpenMP, the flags required to compile with OpenMP
+support are returned in variables for the different languages.  The variables
+may be empty if the compiler does not need a special flag to support OpenMP.
 
 .. versionadded:: 3.5
   Clang support.
 
+Components
+^^^^^^^^^^
+
+This module supports components that can be specified using the standard
+syntax:
+
+.. code-block:: cmake
+
+  find_package(OpenMP [COMPONENTS <components>...])
+
+Each of these components controls the various languages to search OpenMP
+support for.  The following components are exposed:
+
+``C``
+  .. versionadded:: 3.10
+
+``CXX``
+  .. versionadded:: 3.10
+
+``Fortran``
+  .. versionadded:: 3.10
+
+``CUDA``
+  .. versionadded:: 3.31
+
+  The ``CUDA`` language component is supported when using a CUDA compiler
+  that supports OpenMP on the host.
+
+If no components are specified, module checks for all of them automatically.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module provides the following :ref:`Imported Targets`:
+
+``OpenMP::OpenMP_<lang>``
+  .. versionadded:: 3.9
+
+  Target encapsulating the OpenMP usage requirements for language ``<lang>``.
+
 Input Variables
 ^^^^^^^^^^^^^^^
 
@@ -33,25 +75,17 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.10
-  The module exposes the components ``C``, ``CXX``, and ``Fortran``.
-  Each of these controls the various languages to search OpenMP support for.
-
-.. versionadded:: 3.31
-  The ``CUDA`` language component is supported when using a CUDA compiler
-  that supports OpenMP on the host.
-
-Depending on the enabled components the following variables will be set:
+This module defines the following variables:
 
 ``OpenMP_FOUND``
-  Variable indicating that OpenMP flags for all requested languages have been found.
-  If no components are specified, this is true if OpenMP settings for all enabled languages
-  were detected.
+  Boolean variable indicating that OpenMP flags for all requested languages
+  have been found.  If no components are specified, this is true if OpenMP
+  settings for all enabled languages were detected.
 ``OpenMP_VERSION``
-  Minimal version of the OpenMP standard detected among the requested languages,
-  or all enabled languages if no components were specified.
+  Minimal version of the OpenMP standard detected among the requested
+  languages, or all enabled languages if no components were specified.
 
-This module will set the following variables per language in your
+This module will set the following variables per language in the
 project, where ``<lang>`` is one of C, CXX, CUDA, or Fortran:
 
 ``OpenMP_<lang>_FOUND``
@@ -66,23 +100,21 @@
 variables are provided:
 
 ``OpenMP_<lang>_LIB_NAMES``
-  :ref:`;-list <CMake Language Lists>` of libraries for OpenMP programs for ``<lang>``.
+  :ref:`semicolon-separated list <CMake Language Lists>` of libraries for
+  OpenMP programs for ``<lang>``.
 ``OpenMP_<libname>_LIBRARY``
-  Location of the individual libraries needed for OpenMP support in ``<lang>``.
+  Location of the individual libraries needed for OpenMP support in
+  ``<lang>``.
 ``OpenMP_<lang>_LIBRARIES``
   A list of libraries needed to link with OpenMP code written in ``<lang>``.
 
-Additionally, the module provides :prop_tgt:`IMPORTED` targets:
-
-``OpenMP::OpenMP_<lang>``
-  Target for using OpenMP from ``<lang>``.
-
 Specifically for Fortran, the module sets the following variables:
 
 ``OpenMP_Fortran_HAVE_OMPLIB_HEADER``
   Boolean indicating if OpenMP is accessible through ``omp_lib.h``.
 ``OpenMP_Fortran_HAVE_OMPLIB_MODULE``
-  Boolean indicating if OpenMP is accessible through the ``omp_lib`` Fortran module.
+  Boolean indicating if OpenMP is accessible through the ``omp_lib`` Fortran
+  module.
 
 The module will also try to provide the OpenMP version variables:
 
@@ -108,6 +140,17 @@
 Note that this variable is an _input_ control to the module.  Project code
 should use the ``OpenMP_<lang>_INCLUDE_DIRS`` _output_ variable if it needs
 to know what include directories are needed.
+
+Examples
+^^^^^^^^
+
+Finding OpenMP support and linking the imported target to a project target
+using the C language component:
+
+.. code-block:: cmake
+
+  find_package(OpenMP)
+  target_link_libraries(project_target PRIVATE OpenMP::OpenMP_C)
 #]=======================================================================]
 
 cmake_policy(PUSH)
diff --git a/Modules/FindOpenSP.cmake b/Modules/FindOpenSP.cmake
index 3ff6a99..8609210 100644
--- a/Modules/FindOpenSP.cmake
+++ b/Modules/FindOpenSP.cmake
@@ -7,8 +7,14 @@
 
 .. versionadded:: 3.25
 
-Finds the OpenSP library.  OpenSP is an open-source implementation of the SGML
-(Standard Generalized Markup Language) parser.
+Finds the OpenSP library:
+
+.. code-block:: cmake
+
+  find_package(OpenSP [<version>] [...])
+
+OpenSP is an open-source implementation of the SGML (Standard Generalized
+Markup Language) parser.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -25,7 +31,7 @@
 This module defines the following variables:
 
 ``OpenSP_FOUND``
-  Boolean indicating whether the (requested version of) OpenSP is available.
+  Boolean indicating whether (the requested version of) OpenSP is available.
 
 ``OpenSP_VERSION``
   The version of found OpenSP.
diff --git a/Modules/FindOpenSSL.cmake b/Modules/FindOpenSSL.cmake
index af137d4..b817556 100644
--- a/Modules/FindOpenSSL.cmake
+++ b/Modules/FindOpenSSL.cmake
@@ -5,7 +5,11 @@
 FindOpenSSL
 -----------
 
-Finds the installed OpenSSL encryption library and determines its version.
+Finds the installed OpenSSL encryption library and determines its version:
+
+.. code-block:: cmake
+
+  find_package(OpenSSL [<version>] [COMPONENTS <components>...] [...])
 
 .. versionadded:: 3.20
   Support for specifying version range when calling the :command:`find_package`
@@ -95,23 +99,34 @@
 This module defines the following variables:
 
 ``OpenSSL_FOUND``
-  Boolean indicating whether the OpenSSL library has been found.  For backward
-  compatibility, the ``OPENSSL_FOUND`` variable is also set to the same value.
+  Boolean indicating whether (the requested version of) OpenSSL library has
+  been found.  For backward compatibility, the ``OPENSSL_FOUND`` variableđ
+  is also set to the same value.
+
+``OpenSSL_VERSION``
+  .. versionadded:: 4.2
+
+  The OpenSSL version found.  This is set to
+  ``<major>.<minor>.<revision><patch>`` (e.g., ``0.9.8s``).
+
 ``OPENSSL_INCLUDE_DIR``
   The OpenSSL include directory.
+
 ``OPENSSL_CRYPTO_LIBRARY``
   The OpenSSL ``crypto`` library.
+
 ``OPENSSL_CRYPTO_LIBRARIES``
   The OpenSSL ``crypto`` library and its dependencies.
+
 ``OPENSSL_SSL_LIBRARY``
   The OpenSSL ``ssl`` library.
+
 ``OPENSSL_SSL_LIBRARIES``
   The OpenSSL ``ssl`` library and its dependencies.
+
 ``OPENSSL_LIBRARIES``
   All OpenSSL libraries and their dependencies.
-``OPENSSL_VERSION``
-  The OpenSSL version found.  This is set to
-  ``<major>.<minor>.<revision><patch>`` (e.g. ``0.9.8s``).
+
 ``OPENSSL_APPLINK_SOURCE``
   The sources in the target ``OpenSSL::applink`` mentioned above.  This variable
   is only defined if found OpenSSL version is at least 0.9.8 and the platform is
@@ -142,6 +157,17 @@
   ``PKG_CONFIG_PATH`` environment variable to specify alternate locations, which
   is useful on systems with multiple library installations.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``OPENSSL_VERSION``
+  .. deprecated:: 4.2
+    Superseded by the ``OpenSSL_VERSION``.
+
+  The version of OpenSSL found.
+
 Examples
 ^^^^^^^^
 
@@ -661,7 +687,8 @@
       string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING)
     endif ()
 
-    set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}")
+    set(OpenSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}")
+    set(OPENSSL_VERSION "${OpenSSL_VERSION}")
   else ()
     # Since OpenSSL 3.0.0, the new version format is MAJOR.MINOR.PATCH and
     # a new OPENSSL_VERSION_STR macro contains exactly that
@@ -670,10 +697,11 @@
     string(REGEX REPLACE "^.*OPENSSL_VERSION_STR[\t ]+\"([0-9]+\\.[0-9]+\\.[0-9]+)\".*$"
            "\\1" OPENSSL_VERSION_STR "${OPENSSL_VERSION_STR}")
 
-    set(OPENSSL_VERSION "${OPENSSL_VERSION_STR}")
+    set(OpenSSL_VERSION "${OPENSSL_VERSION_STR}")
+    set(OPENSSL_VERSION "${OpenSSL_VERSION}")
 
     # Setting OPENSSL_VERSION_MAJOR OPENSSL_VERSION_MINOR and OPENSSL_VERSION_FIX
-    string(REGEX MATCHALL "([0-9])+" OPENSSL_VERSION_NUMBER "${OPENSSL_VERSION}")
+    string(REGEX MATCHALL "([0-9])+" OPENSSL_VERSION_NUMBER "${OpenSSL_VERSION}")
     list(POP_FRONT OPENSSL_VERSION_NUMBER
       OPENSSL_VERSION_MAJOR
       OPENSSL_VERSION_MINOR
@@ -718,7 +746,7 @@
     OPENSSL_CRYPTO_LIBRARY
     OPENSSL_INCLUDE_DIR
   VERSION_VAR
-    OPENSSL_VERSION
+    OpenSSL_VERSION
   HANDLE_VERSION_RANGE
   HANDLE_COMPONENTS
   FAIL_MESSAGE
diff --git a/Modules/FindOpenSceneGraph.cmake b/Modules/FindOpenSceneGraph.cmake
index 26f406d..5cd0d16 100644
--- a/Modules/FindOpenSceneGraph.cmake
+++ b/Modules/FindOpenSceneGraph.cmake
@@ -5,7 +5,11 @@
 FindOpenSceneGraph
 ------------------
 
-Finds `OpenSceneGraph`_ (OSG), a 3D graphics application programming interface.
+Finds `OpenSceneGraph`_ (OSG), a 3D graphics application programming interface:
+
+.. code-block:: cmake
+
+  find_package(OpenSceneGraph [<version>] [COMPONENTS <components>...] [...])
 
 .. note::
 
@@ -153,12 +157,14 @@
 This module defines the following variables:
 
 ``OpenSceneGraph_FOUND``
-  Boolean indicating whether the (requested version of) OpenSceneGraph with all
+  Boolean indicating whether (the requested version of) OpenSceneGraph with all
   specified components is found.  For backward compatibility, the
   ``OPENSCENEGRAPH_FOUND`` variable is also set to the same value.
 
-``OPENSCENEGRAPH_VERSION``
-  The version of the OSG which was found.
+``OpenSceneGraph_VERSION``
+  .. versionadded:: 4.2
+
+  The version of OpenSceneGraph found.
 
 ``OPENSCENEGRAPH_INCLUDE_DIRS``
   Include directories containing headers needed to use OpenSceneGraph.
@@ -197,6 +203,17 @@
 ``OSG_ROOT``
   Environment variable treated the same as ``OSG_DIR``.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``OPENSCENEGRAPH_VERSION``
+  .. deprecated:: 4.2
+    Superseded by the ``OpenSceneGraph_VERSION``.
+
+  The version of OpenSceneGraph found.
+
 Examples
 ^^^^^^^^
 
@@ -324,9 +341,11 @@
 
     set(OPENSCENEGRAPH_VERSION "${_osg_VERSION_MAJOR}.${_osg_VERSION_MINOR}.${_osg_VERSION_PATCH}"
                                 CACHE INTERNAL "The version of OSG which was detected")
+    set(OpenSceneGraph_VERSION "${OPENSCENEGRAPH_VERSION}")
+
     if(OpenSceneGraph_DEBUG)
         message(STATUS "[ FindOpenSceneGraph.cmake:${CMAKE_CURRENT_LIST_LINE} ] "
-            "Detected version ${OPENSCENEGRAPH_VERSION}")
+            "Detected version ${OpenSceneGraph_VERSION}")
     endif()
 endif()
 
@@ -374,7 +393,7 @@
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(OpenSceneGraph
                                   REQUIRED_VARS OPENSCENEGRAPH_LIBRARIES OPENSCENEGRAPH_INCLUDE_DIR ${_osg_component_founds}
-                                  VERSION_VAR OPENSCENEGRAPH_VERSION)
+                                  VERSION_VAR OpenSceneGraph_VERSION)
 
 unset(_osg_component_founds)
 
diff --git a/Modules/FindOpenThreads.cmake b/Modules/FindOpenThreads.cmake
index 2e7c84f..91d4b06 100644
--- a/Modules/FindOpenThreads.cmake
+++ b/Modules/FindOpenThreads.cmake
@@ -5,7 +5,11 @@
 FindOpenThreads
 ---------------
 
-Finds the OpenThreads C++ based threading library.
+Finds the OpenThreads C++ based threading library:
+
+.. code-block:: cmake
+
+  find_package(OpenThreads [...])
 
 OpenThreads header files are intended to be included as:
 
diff --git a/Modules/FindPHP4.cmake b/Modules/FindPHP4.cmake
index edef791..4a8862c 100644
--- a/Modules/FindPHP4.cmake
+++ b/Modules/FindPHP4.cmake
@@ -5,7 +5,11 @@
 FindPHP4
 --------
 
-Finds PHP version 4, a general-purpose scripting language.
+Finds PHP version 4, a general-purpose scripting language:
+
+.. code-block:: cmake
+
+  find_package(PHP4 [...])
 
 .. note::
 
diff --git a/Modules/FindPNG.cmake b/Modules/FindPNG.cmake
index 1a72f7d..a954527 100644
--- a/Modules/FindPNG.cmake
+++ b/Modules/FindPNG.cmake
@@ -5,7 +5,11 @@
 FindPNG
 -------
 
-Finds libpng, the official reference library for the PNG image format.
+Finds libpng, the official reference library for the PNG image format:
+
+.. code-block:: cmake
+
+  find_package(PNG [<version>] [...])
 
 .. note::
 
@@ -15,41 +19,61 @@
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.5
-
-This module defines the following :ref:`Imported Targets`:
+This module provides the following :ref:`Imported Targets`:
 
 ``PNG::PNG``
-  The libpng library, if found.
+  .. versionadded:: 3.5
+
+  Target encapsulating the libpng library usage requirements, available if
+  libpng is found.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
+
+``PNG_FOUND``
+  Boolean indicating whether (the requested version of) PNG library is found.
+
+``PNG_VERSION``
+  .. versionadded:: 4.2
+
+  The version of the PNG library found.
 
 ``PNG_INCLUDE_DIRS``
   Directory containing the PNG headers (e.g., ``png.h``).
+
 ``PNG_LIBRARIES``
   PNG libraries required for linking.
+
 ``PNG_DEFINITIONS``
   Compile definitions for using PNG, if any.  They can be added with
   :command:`target_compile_definitions` command when not using the ``PNG::PNG``
   imported target.
-``PNG_FOUND``
-  True if PNG library is found.
-``PNG_VERSION_STRING``
-  The version of the PNG library found.
 
-Obsolete Variables
-^^^^^^^^^^^^^^^^^^
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
 
 The following variables may also be set for backward compatibility:
 
 ``PNG_LIBRARY``
+  .. deprecated:: 3.0
+    Use the ``PNG::PNG`` imported target.
+
   Path to the PNG library.
+
 ``PNG_INCLUDE_DIR``
+  .. deprecated:: 3.0
+    Use the ``PNG::PNG`` imported target.
+
   Directory containing the PNG headers (same as ``PNG_INCLUDE_DIRS``).
 
+``PNG_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``PNG_VERSION``.
+
+  The version of the PNG library found.
+
 Examples
 ^^^^^^^^
 
@@ -184,7 +208,8 @@
   if (PNG_PNG_INCLUDE_DIR AND EXISTS "${PNG_PNG_INCLUDE_DIR}/png.h")
       file(STRINGS "${PNG_PNG_INCLUDE_DIR}/png.h" png_version_str REGEX "^#define[ \t]+PNG_LIBPNG_VER_STRING[ \t]+\".+\"")
 
-      string(REGEX REPLACE "^#define[ \t]+PNG_LIBPNG_VER_STRING[ \t]+\"([^\"]+)\".*" "\\1" PNG_VERSION_STRING "${png_version_str}")
+      string(REGEX REPLACE "^#define[ \t]+PNG_LIBPNG_VER_STRING[ \t]+\"([^\"]+)\".*" "\\1" PNG_VERSION "${png_version_str}")
+      set(PNG_VERSION_STRING "${PNG_VERSION}")
       unset(png_version_str)
   endif ()
 endif()
@@ -192,6 +217,6 @@
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(PNG
                                   REQUIRED_VARS PNG_LIBRARY PNG_PNG_INCLUDE_DIR
-                                  VERSION_VAR PNG_VERSION_STRING)
+                                  VERSION_VAR PNG_VERSION)
 
 cmake_policy(POP)
diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake
index 5081936..b4c7291 100644
--- a/Modules/FindPackageHandleStandardArgs.cmake
+++ b/Modules/FindPackageHandleStandardArgs.cmake
@@ -5,28 +5,42 @@
 FindPackageHandleStandardArgs
 -----------------------------
 
-This module provides functions intended to be used in :ref:`Find Modules`
+This module provides commands intended to be used in :ref:`Find Modules`
 implementing :command:`find_package(<PackageName>)` calls.
 
+Load this module in a CMake find module with:
+
+.. code-block:: cmake
+  :caption: ``FindFoo.cmake``
+
+  include(FindPackageHandleStandardArgs)
+
+Commands
+^^^^^^^^
+
+This module provides the following commands:
+
+* :command:`find_package_handle_standard_args`
+* :command:`find_package_check_version`
+
 .. command:: find_package_handle_standard_args
 
-  This command handles the ``REQUIRED``, ``QUIET`` and version-related
-  arguments of :command:`find_package`.  It also sets the
-  ``<PackageName>_FOUND`` variable.  The package is considered found if all
-  variables listed contain valid results, e.g. valid filepaths.
+  Handles the ``REQUIRED``, ``QUIET`` and version-related arguments of
+  :command:`find_package`.
 
   There are two signatures:
 
   .. code-block:: cmake
 
-    find_package_handle_standard_args(<PackageName>
+    find_package_handle_standard_args(
+      <PackageName>
       (DEFAULT_MSG|<custom-failure-message>)
-      <required-var>...
-      )
+      <required-vars>...
+    )
 
-    find_package_handle_standard_args(<PackageName>
-      [FOUND_VAR <result-var>]
-      [REQUIRED_VARS <required-var>...]
+    find_package_handle_standard_args(
+      <PackageName>
+      [REQUIRED_VARS <required-vars>...]
       [VERSION_VAR <version-var>]
       [HANDLE_VERSION_RANGE]
       [HANDLE_COMPONENTS]
@@ -34,37 +48,33 @@
       [NAME_MISMATCHED]
       [REASON_FAILURE_MESSAGE <reason-failure-message>]
       [FAIL_MESSAGE <custom-failure-message>]
-      )
+      [FOUND_VAR <result-var>] # Deprecated
+    )
 
-  The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all
-  the variables ``<required-var>...`` are valid and any optional
-  constraints are satisfied, and ``FALSE`` otherwise.  A success or
-  failure message may be displayed based on the results and on
-  whether the ``REQUIRED`` and/or ``QUIET`` option was given to
-  the :command:`find_package` call.
+  This command sets the ``<PackageName>_FOUND`` variable to ``TRUE`` if all
+  the variables listed in ``<required-vars>...`` contain valid results
+  (e.g., valid filepaths) and any optional constraints are satisfied, and
+  ``FALSE`` otherwise.  A success or failure message may be displayed based
+  on the results and on whether the ``REQUIRED`` and/or ``QUIET`` option
+  was given to the :command:`find_package` call.
 
-  The options are:
+  The arguments are:
+
+  ``<PackageName>``
+    The name of the package.  For example, as written in the
+    ``Find<PackageName>.cmake`` find module filename.
 
   ``(DEFAULT_MSG|<custom-failure-message>)``
     In the simple signature this specifies the failure message.
     Use ``DEFAULT_MSG`` to ask for a default message to be computed
     (recommended).  Not valid in the full signature.
 
-  ``FOUND_VAR <result-var>``
-    .. deprecated:: 3.3
-
-    Specifies either ``<PackageName>_FOUND`` or
-    ``<PACKAGENAME>_FOUND`` as the result variable.  This exists only
-    for compatibility with older versions of CMake and is now ignored.
-    Result variables of both names are now always set for compatibility
-    also with or without this option.
-
-  ``REQUIRED_VARS <required-var>...``
+  ``REQUIRED_VARS <required-vars>...``
     Specify the variables which are required for this package.
     These may be named in the generated failure message asking the
     user to set the missing variable values.  Therefore these should
-    typically be cache entries such as ``FOO_LIBRARY`` and not output
-    variables like ``FOO_LIBRARIES``.
+    typically be cache entries such as ``Foo_LIBRARY`` and not output
+    variables like ``Foo_LIBRARIES``.
 
     .. versionchanged:: 3.18
       If ``HANDLE_COMPONENTS`` is specified, this option can be omitted.
@@ -100,6 +110,14 @@
     will automatically check whether the package configuration file
     was found.
 
+  ``NAME_MISMATCHED``
+    .. versionadded:: 3.17
+
+    Indicate that the ``<PackageName>`` does not match the value of
+    :variable:`CMAKE_FIND_PACKAGE_NAME` variable. This is usually a mistake
+    and raises a warning, but it may be intentional for usage of the
+    command for components of a larger package.
+
   ``REASON_FAILURE_MESSAGE <reason-failure-message>``
     .. versionadded:: 3.16
 
@@ -110,48 +128,76 @@
     Specify a custom failure message instead of using the default
     generated message.  Not recommended.
 
-  ``NAME_MISMATCHED``
-    .. versionadded:: 3.17
+  ``FOUND_VAR <result-var>``
+    .. deprecated:: 3.3
+      This option should no longer be used.
 
-    Indicate that the ``<PackageName>`` does not match
-    ``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a
-    warning, but it may be intentional for usage of the command for components
-    of a larger package.
+    Specifies either ``<PackageName>_FOUND`` or ``<PACKAGENAME>_FOUND`` as the
+    result variable.  This exists only for backward compatibility with older
+    versions of CMake and is now ignored.  Result variables of both names are
+    now always set for compatibility also with or without this option.
 
-Example for the simple signature:
+  .. note::
+
+    If ``<PackageName>`` does not match :variable:`CMAKE_FIND_PACKAGE_NAME`
+    for the calling module, a warning that there is a mismatch is given.  The
+    ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using
+    the old signature and the ``NAME_MISMATCHED`` argument using the new
+    signature.  To avoid forcing the caller to require newer versions of CMake
+    for usage, the variable's value will be used if defined when the
+    ``NAME_MISMATCHED`` argument is not passed for the new signature (but using
+    both is an error).
+
+.. command:: find_package_check_version
+
+  .. versionadded:: 3.19
+
+  Checks if a given version is valid against the version-related arguments
+  of :command:`find_package`:
+
+  .. code-block:: cmake
+
+    find_package_check_version(
+      <version>
+      <result-var>
+      [HANDLE_VERSION_RANGE]
+      [RESULT_MESSAGE_VARIABLE <message-var>]
+    )
+
+  The arguments are:
+
+  ``<version>``
+    The version string to check.
+
+  ``<result-var>``
+    Name of the result variable that will hold a boolean value giving the
+    result of the check.
+
+  ``HANDLE_VERSION_RANGE``
+    Enable handling of a version range, if one is specified.  Without this
+    option, a developer warning will be displayed if a version range is
+    specified.
+
+  ``RESULT_MESSAGE_VARIABLE <message-var>``
+    Specify a variable to get back a message describing the result of the check.
+
+Examples
+^^^^^^^^
+
+Examples: Full Signature
+""""""""""""""""""""""""
+
+Example for using a full signature of ``find_package_handle_standard_args()``:
 
 .. code-block:: cmake
+  :caption: ``FindLibArchive.cmake``
 
-  find_package_handle_standard_args(LibXml2 DEFAULT_MSG
-    LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
-
-The ``LibXml2`` package is considered to be found if both
-``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.
-Then also ``LibXml2_FOUND`` is set to ``TRUE``.  If it is not found
-and ``REQUIRED`` was used, it fails with a
-:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was
-used or not.  If it is found, success will be reported, including
-the content of the first ``<required-var>``.  On repeated CMake runs,
-the same message will not be printed again.
-
-.. note::
-
-  If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the
-  calling module, a warning that there is a mismatch is given. The
-  ``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using
-  the old signature and the ``NAME_MISMATCHED`` argument using the new
-  signature. To avoid forcing the caller to require newer versions of CMake for
-  usage, the variable's value will be used if defined when the
-  ``NAME_MISMATCHED`` argument is not passed for the new signature (but using
-  both is an error)..
-
-Example for the full signature:
-
-.. code-block:: cmake
-
-  find_package_handle_standard_args(LibArchive
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(
+    LibArchive
     REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
-    VERSION_VAR LibArchive_VERSION)
+    VERSION_VAR LibArchive_VERSION
+  )
 
 In this case, the ``LibArchive`` package is considered to be found if
 both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.
@@ -159,56 +205,73 @@
 contained in ``LibArchive_VERSION``.  Since no ``FAIL_MESSAGE`` is given,
 the default messages will be printed.
 
-Another example for the full signature:
+Another example for the full signature of
+``find_package_handle_standard_args()``:
 
 .. code-block:: cmake
+  :caption: ``FindAutomoc4.cmake``
 
   find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
-  find_package_handle_standard_args(Automoc4  CONFIG_MODE)
 
-In this case, a ``FindAutmoc4.cmake`` module wraps a call to
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Automoc4 CONFIG_MODE)
+
+In this case, a ``FindAutomoc4.cmake`` module wraps a call to
 ``find_package(Automoc4 NO_MODULE)`` and adds an additional search
 directory for ``automoc4``.  Then the call to
-``find_package_handle_standard_args`` produces a proper success/failure
+``find_package_handle_standard_args()`` produces a proper success/failure
 message.
 
-.. command:: find_package_check_version
+Example: Simple Signature
+"""""""""""""""""""""""""
 
-  .. versionadded:: 3.19
-
-  Helper function which can be used to check if a ``<version>`` is valid
-  against version-related arguments of :command:`find_package`.
-
-  .. code-block:: cmake
-
-    find_package_check_version(<version> <result-var>
-      [HANDLE_VERSION_RANGE]
-      [RESULT_MESSAGE_VARIABLE <message-var>]
-      )
-
-  The ``<result-var>`` will hold a boolean value giving the result of the check.
-
-  The options are:
-
-  ``HANDLE_VERSION_RANGE``
-    Enable handling of a version range, if one is specified. Without this
-    option, a developer warning will be displayed if a version range is
-    specified.
-
-  ``RESULT_MESSAGE_VARIABLE <message-var>``
-    Specify a variable to get back a message describing the result of the check.
-
-Example for the usage:
+Example for using a simple signature of ``find_package_handle_standard_args()``:
 
 .. code-block:: cmake
+  :caption: ``FindLibXml2.cmake``
 
-  find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE
-    RESULT_MESSAGE_VARIABLE reason)
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(
+    LibXml2
+    DEFAULT_MSG
+    LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR
+  )
+
+In this example, the ``LibXml2`` package is considered to be found if both
+``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` variables are valid.  Then
+also ``LibXml2_FOUND`` is set to ``TRUE``.  If it is not found and
+``REQUIRED`` was used, it fails with a :command:`message(FATAL_ERROR)`,
+independent whether ``QUIET`` was used or not.  If it is found, success will
+be reported, including the content of the first required variable specified
+in ``<required-vars>...``.  On repeated CMake runs, the same message will
+not be printed again.
+
+Example: Checking Version
+"""""""""""""""""""""""""
+
+Example for the ``find_package_check_version()`` usage:
+
+.. code-block:: cmake
+  :caption: ``FindFoo.cmake``
+
+  include(FindPackageHandleStandardArgs)
+  find_package_check_version(
+    1.2.3
+    result
+    HANDLE_VERSION_RANGE
+    RESULT_MESSAGE_VARIABLE reason
+  )
   if(result)
     message(STATUS "${reason}")
   else()
-    message(FATAL_ERROR "${reason}")
+    # Logic when version check is not successful.
+    message(WARNING "${reason}")
   endif()
+
+See Also
+^^^^^^^^
+
+* :ref:`Find Modules` for details how to write a find module.
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
diff --git a/Modules/FindPerl.cmake b/Modules/FindPerl.cmake
index 06a2e62..b1c4f51 100644
--- a/Modules/FindPerl.cmake
+++ b/Modules/FindPerl.cmake
@@ -5,8 +5,13 @@
 FindPerl
 --------
 
-Finds a Perl interpreter.  Perl is a general-purpose, interpreted, dynamic
-programming language.
+Finds a Perl interpreter:
+
+.. code-block:: cmake
+
+  find_package(Perl [<version>] [...])
+
+Perl is a general-purpose, interpreted, dynamic programming language.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -14,10 +19,13 @@
 This module defines the following variables:
 
 ``Perl_FOUND``
-  True if the Perl executable was found.  For backward compatibility, the
-  ``PERL_FOUND`` variable is also set to the same value.
+  Boolean indicating whether the (requested version of) Perl executable is
+  found.  For backward compatibility, the ``PERL_FOUND`` variable is also
+  set to the same value.
 
-``PERL_VERSION_STRING``
+``Perl_VERSION``
+  .. versionadded:: 4.2
+
   The version of Perl found.
 
 Cache Variables
@@ -28,14 +36,34 @@
 ``PERL_EXECUTABLE``
   Full path to the ``perl`` executable.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``PERL_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``Perl_VERSION``.
+
+  The version of Perl found.
+
 Examples
 ^^^^^^^^
 
-Finding the Perl interpreter:
+Finding the Perl interpreter and executing it in a process:
 
 .. code-block:: cmake
 
   find_package(Perl)
+
+  if(Perl_FOUND)
+    execute_process(COMMAND ${PERL_EXECUTABLE} --help)
+  endif()
+
+See Also
+^^^^^^^^
+
+* The :module:`FindPerlLibs` to find Perl libraries.
 #]=======================================================================]
 
 include(${CMAKE_CURRENT_LIST_DIR}/FindCygwin.cmake)
@@ -64,7 +92,6 @@
   )
 
 if(PERL_EXECUTABLE)
-  ### PERL_VERSION
   execute_process(
     COMMAND
       ${PERL_EXECUTABLE} -V:version
@@ -76,7 +103,8 @@
       OUTPUT_STRIP_TRAILING_WHITESPACE
   )
   if(NOT PERL_VERSION_RESULT_VARIABLE AND NOT PERL_VERSION_OUTPUT_VARIABLE MATCHES "^version='UNKNOWN'")
-    string(REGEX REPLACE "version='([^']+)'.*" "\\1" PERL_VERSION_STRING ${PERL_VERSION_OUTPUT_VARIABLE})
+    string(REGEX REPLACE "version='([^']+)'.*" "\\1" Perl_VERSION ${PERL_VERSION_OUTPUT_VARIABLE})
+    set(PERL_VERSION_STRING "${Perl_VERSION}")
   else()
     execute_process(
       COMMAND ${PERL_EXECUTABLE} -v
@@ -86,9 +114,11 @@
       OUTPUT_STRIP_TRAILING_WHITESPACE
     )
     if(NOT PERL_VERSION_RESULT_VARIABLE AND PERL_VERSION_OUTPUT_VARIABLE MATCHES "This is perl.*[ \\(]v([0-9\\._]+)[ \\)]")
-      set(PERL_VERSION_STRING "${CMAKE_MATCH_1}")
+      set(Perl_VERSION "${CMAKE_MATCH_1}")
+      set(PERL_VERSION_STRING "${Perl_VERSION}")
     elseif(NOT PERL_VERSION_RESULT_VARIABLE AND PERL_VERSION_OUTPUT_VARIABLE MATCHES "This is perl, version ([0-9\\._]+) +")
-      set(PERL_VERSION_STRING "${CMAKE_MATCH_1}")
+      set(Perl_VERSION "${CMAKE_MATCH_1}")
+      set(PERL_VERSION_STRING "${Perl_VERSION}")
     endif()
   endif()
 endif()
@@ -105,7 +135,7 @@
 endif ()
 find_package_handle_standard_args(Perl
                                   REQUIRED_VARS PERL_EXECUTABLE
-                                  VERSION_VAR PERL_VERSION_STRING)
+                                  VERSION_VAR Perl_VERSION)
 unset(FPHSA_NAME_MISMATCHED)
 
 mark_as_advanced(PERL_EXECUTABLE)
diff --git a/Modules/FindPerlLibs.cmake b/Modules/FindPerlLibs.cmake
index 330700e..ab6b333 100644
--- a/Modules/FindPerlLibs.cmake
+++ b/Modules/FindPerlLibs.cmake
@@ -5,18 +5,33 @@
 FindPerlLibs
 ------------
 
-Finds Perl libraries.  Perl is a general-purpose, interpreted, dynamic
-programming language.  This module detects whether Perl is installed and
-determines the locations of include paths, libraries, and the library name.
+Finds Perl libraries:
+
+.. code-block:: cmake
+
+  find_package(PerlLibs [<version>] [...])
+
+Perl is a general-purpose, interpreted, dynamic programming language.
+
+This module detects whether Perl interpreter is installed via the
+:module:`FindPerl` module and determines the locations of Perl include paths,
+libraries, and the library name.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``PerlLibs_FOUND``
-  True if ``perl.h`` and ``libperl`` were found.  For backward compatibility,
-  the ``PERLLIBS_FOUND`` variable is also set to the same value.
+  Boolean indicating whether the (requested version of) Perl library
+  (``perl.h`` and ``libperl``) is found.  For backward compatibility, the
+  ``PERLLIBS_FOUND`` variable is also set to the same value.
+
+``PerlLibs_VERSION``
+  .. versionadded:: 4.2
+
+  The version of Perl library found.
+
 ``PERL_SITESEARCH``
   Path to the sitesearch install directory (``-V:installsitesearch``).
 ``PERL_SITEARCH``
@@ -58,11 +73,18 @@
 .. code-block:: cmake
 
   find_package(PerlLibs 6.0)
+
+See Also
+^^^^^^^^
+
+* The :module:`FindPerl` module to find the Perl interpreter.
 #]=======================================================================]
 
 # find the perl executable
 include(${CMAKE_CURRENT_LIST_DIR}/FindPerl.cmake)
 
+set(PerlLibs_VERSION "${Perl_VERSION}")
+
 if (PERL_EXECUTABLE)
 
   function (perl_get_info _pgi_info tag)
@@ -122,10 +144,10 @@
   ### PERL_POSSIBLE_LIBRARY_NAMES
   perl_get_info(PERL_POSSIBLE_LIBRARY_NAMES libperl)
   if (NOT PERL_POSSIBLE_LIBRARY_NAMES)
-    set(PERL_POSSIBLE_LIBRARY_NAMES perl${PERL_VERSION_STRING} perl)
+    set(PERL_POSSIBLE_LIBRARY_NAMES perl${PerlLibs_VERSION} perl)
   endif()
   if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN")
-    list (APPEND PERL_POSSIBLE_LIBRARY_NAMES perl${PERL_VERSION_STRING})
+    list (APPEND PERL_POSSIBLE_LIBRARY_NAMES perl${PerlLibs_VERSION})
   endif()
   if (CMAKE_SYSTEM_NAME MATCHES "MSYS|CYGWIN")
     # On MSYS and CYGWIN environments, current perl -V:libperl gives shared
@@ -141,10 +163,10 @@
     PATHS
       "${PERL_UPDATE_ARCHLIB}/CORE"
       "${PERL_ARCHLIB}/CORE"
-      /usr/lib/perl5/${PERL_VERSION_STRING}/${PERL_ARCHNAME}/CORE
-      /usr/lib/perl/${PERL_VERSION_STRING}/${PERL_ARCHNAME}/CORE
-      /usr/lib/perl5/${PERL_VERSION_STRING}/CORE
-      /usr/lib/perl/${PERL_VERSION_STRING}/CORE
+      /usr/lib/perl5/${PerlLibs_VERSION}/${PERL_ARCHNAME}/CORE
+      /usr/lib/perl/${PerlLibs_VERSION}/${PERL_ARCHNAME}/CORE
+      /usr/lib/perl5/${PerlLibs_VERSION}/CORE
+      /usr/lib/perl/${PerlLibs_VERSION}/CORE
   )
 
   ### PERL_LIBRARY
@@ -154,24 +176,24 @@
     PATHS
       "${PERL_UPDATE_ARCHLIB}/CORE"
       "${PERL_ARCHLIB}/CORE"
-      /usr/lib/perl5/${PERL_VERSION_STRING}/${PERL_ARCHNAME}/CORE
-      /usr/lib/perl/${PERL_VERSION_STRING}/${PERL_ARCHNAME}/CORE
-      /usr/lib/perl5/${PERL_VERSION_STRING}/CORE
-      /usr/lib/perl/${PERL_VERSION_STRING}/CORE
+      /usr/lib/perl5/${PerlLibs_VERSION}/${PERL_ARCHNAME}/CORE
+      /usr/lib/perl/${PerlLibs_VERSION}/${PERL_ARCHNAME}/CORE
+      /usr/lib/perl5/${PerlLibs_VERSION}/CORE
+      /usr/lib/perl/${PerlLibs_VERSION}/CORE
   )
 
 endif ()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(PerlLibs REQUIRED_VARS PERL_LIBRARY PERL_INCLUDE_PATH
-                                           VERSION_VAR PERL_VERSION_STRING)
+                                           VERSION_VAR PerlLibs_VERSION)
 
 # Introduced after CMake 2.6.4 to bring module into compliance
 set(PERL_INCLUDE_DIR  ${PERL_INCLUDE_PATH})
 set(PERL_INCLUDE_DIRS ${PERL_INCLUDE_PATH})
 set(PERL_LIBRARIES    ${PERL_LIBRARY})
 # For backward compatibility with CMake before 2.8.8
-set(PERL_VERSION ${PERL_VERSION_STRING})
+set(PERL_VERSION ${PerlLibs_VERSION})
 
 mark_as_advanced(
   PERL_INCLUDE_PATH
diff --git a/Modules/FindPhysFS.cmake b/Modules/FindPhysFS.cmake
index 1894498..fae4421 100644
--- a/Modules/FindPhysFS.cmake
+++ b/Modules/FindPhysFS.cmake
@@ -5,7 +5,11 @@
 FindPhysFS
 ----------
 
-Finds the PhysicsFS library (PhysFS) for file I/O abstraction.
+Finds the PhysicsFS library (PhysFS) for file I/O abstraction:
+
+.. code-block:: cmake
+
+  find_package(PhysFS [...])
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -21,11 +25,11 @@
 
 The following cache variables may also be set:
 
+``PHYSFS_INCLUDE_DIR``
+  Directory containing the ``<physfs.h>`` and related headers needed for using
+  the library.
 ``PHYSFS_LIBRARY``
   Path to the PhysicsFS library needed to link against.
-``PHYSFS_INCLUDE_DIR``
-  Directory containing the ``physfs.h`` and related headers needed for using
-  the library.
 
 Hints
 ^^^^^
diff --git a/Modules/FindPkgConfig.cmake b/Modules/FindPkgConfig.cmake
index b230eb5..91c71ae 100644
--- a/Modules/FindPkgConfig.cmake
+++ b/Modules/FindPkgConfig.cmake
@@ -7,28 +7,454 @@
 
 A ``pkg-config`` module for CMake.
 
-Finds the ``pkg-config`` executable and adds the :command:`pkg_get_variable`,
-:command:`pkg_check_modules` and :command:`pkg_search_module` commands. The
-following variables will also be set:
+Finds the ``pkg-config`` executable and provides commands to use it in
+CMake:
+
+.. code-block:: cmake
+
+  find_package(PkgConfig [<version>] [QUIET] [REQUIRED] [...])
+
+``pkg-config`` is a command-line program for configuring build dependency
+information.  Initially developed by FreeDesktop, it is also available in
+several implementations, such as pkgconf, u-config, and similar.  It reads
+package data from the so-called PC metadata files (``<module-name>.pc``)
+that may come installed with packages.  This module is a wrapper around the
+``pkg-config`` command-line executable.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
 
 ``PKG_CONFIG_FOUND``
-  True if a pkg-config executable was found.
+  Boolean indicating whether the (requested version of) ``pkg-config``
+  executable is found.
 
 ``PKG_CONFIG_VERSION_STRING``
-  The version of pkg-config that was found.
+  The version of ``pkg-config`` that was found.
 
 ``PKG_CONFIG_EXECUTABLE``
-  The pathname of the pkg-config program.
+  The pathname of the ``pkg-config`` program.
 
 ``PKG_CONFIG_ARGN``
   .. versionadded:: 3.22
 
-  A list of arguments to pass to pkg-config.
+  A list of arguments to pass to ``pkg-config``.
 
 Both ``PKG_CONFIG_EXECUTABLE`` and ``PKG_CONFIG_ARGN`` are initialized by the
-module, but may be overridden by the user.  See `Variables Affecting Behavior`_
-for how these variables are initialized.
+module, but may be overridden by the user.  See `Hints`_ for how these
+variables are initialized.
 
+Commands
+^^^^^^^^
+
+This module provides the following commands, if ``pkg-config`` is found:
+
+* :command:`pkg_check_modules`
+* :command:`pkg_search_module`
+* :command:`pkg_get_variable`
+
+.. command:: pkg_check_modules
+
+  Checks for all the given modules, setting a variety of result variables
+  in the calling scope:
+
+  .. code-block:: cmake
+
+    pkg_check_modules(
+      <prefix>
+      [QUIET]
+      [REQUIRED]
+      [NO_CMAKE_PATH]
+      [NO_CMAKE_ENVIRONMENT_PATH]
+      [IMPORTED_TARGET [GLOBAL]]
+      <module-spec> [<module-spec>...]
+    )
+
+  .. rubric:: The arguments are:
+
+  ``<prefix>``
+    Prefix string prepended to result variables for the specified modules.
+
+  ``QUIET``
+    When this argument is given, no status messages will be printed.
+
+  ``REQUIRED``
+    When this argument is given, the command will fail with an error if any
+    of the specified module(s) could not be found.
+
+  ``NO_CMAKE_PATH``, ``NO_CMAKE_ENVIRONMENT_PATH``
+    .. versionadded:: 3.3
+
+    The :variable:`CMAKE_PREFIX_PATH`,
+    :variable:`CMAKE_FRAMEWORK_PATH`, and :variable:`CMAKE_APPBUNDLE_PATH` cache
+    and environment variables will be added to the ``pkg-config`` search path.
+    The ``NO_CMAKE_PATH`` and ``NO_CMAKE_ENVIRONMENT_PATH`` arguments
+    disable this behavior for the cache variables and environment variables
+    respectively.
+    The ``PKG_CONFIG_USE_CMAKE_PREFIX_PATH`` variable set to ``FALSE``
+    disables this behavior globally.
+
+    .. This was actually added in 3.1, but didn't work until 3.3.
+
+  ``IMPORTED_TARGET [GLOBAL]``
+    .. versionadded:: 3.7
+
+    This argument will create an :ref:`imported target <Imported Targets>`
+    named ``PkgConfig::<prefix>`` that can be passed directly as an argument
+    to :command:`target_link_libraries`.  It will encapsulate usage
+    requirements for all specified modules ``<module-spec>...`` at once.
+
+    .. This was actually added in 3.6, but didn't work until 3.7.
+
+    ``GLOBAL``
+      .. versionadded:: 3.13
+
+      This argument is used together with ``IMPORTED_TARGET`` and will make
+      the imported target available in global scope.
+
+    .. versionadded:: 3.15
+      Non-library linker options reported by ``pkg-config`` are stored in the
+      :prop_tgt:`INTERFACE_LINK_OPTIONS` target property.
+
+    .. versionchanged:: 3.18
+      Include directories specified with ``-isystem`` are stored in the
+      :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property.  Previous
+      versions of CMake left them in the :prop_tgt:`INTERFACE_COMPILE_OPTIONS`
+      property.
+
+  ``<module-spec>``
+    Each ``<module-spec>`` can be either a bare module name (as defined in
+    its PC metadata file name ``<module-name>.pc``) or it can be a module
+    name with a version constraint (operators ``=``, ``<``, ``>``, ``<=``
+    and ``>=`` are supported).  The following are examples for a module
+    named ``foo`` with various constraints:
+
+    - ``foo`` matches any version.
+    - ``foo<2`` only matches versions before 2.
+    - ``foo>=3.1`` matches any version from 3.1 or later.
+    - ``foo=1.2.3`` requires that foo must be exactly version 1.2.3.
+
+  .. rubric:: Result Variables
+
+  The following variables may be set upon return.  Two sets of values exist:
+  One for the common case (``<XXX> = <prefix>``) and another for the
+  information ``pkg-config`` provides when called with the ``--static``
+  option (``<XXX> = <prefix>_STATIC``).
+
+  ``<XXX>_FOUND``
+    Boolean variable set to 1 if module(s) exist.
+  ``<XXX>_LIBRARIES``
+    A list of only the libraries (without the ``-l``).
+  ``<XXX>_LINK_LIBRARIES``
+    The libraries and their absolute paths.
+  ``<XXX>_LIBRARY_DIRS``
+    The paths of the libraries (without the ``-L``).
+  ``<XXX>_LDFLAGS``
+    All required linker flags.
+  ``<XXX>_LDFLAGS_OTHER``
+    All other linker flags.
+  ``<XXX>_INCLUDE_DIRS``
+    The ``-I`` preprocessor flags (without the ``-I``).
+  ``<XXX>_CFLAGS``
+    All required cflags.
+  ``<XXX>_CFLAGS_OTHER``
+    The other compiler flags.
+
+  All but ``<XXX>_FOUND`` may be a :ref:`semicolon-separated list
+  <CMake Language Lists>` if the
+  associated variable returned from ``pkg-config`` has multiple values.
+
+  .. versionchanged:: 3.18
+    Include directories specified with ``-isystem`` are stored in the
+    ``<XXX>_INCLUDE_DIRS`` variable.  Previous versions of CMake left them
+    in ``<XXX>_CFLAGS_OTHER``.
+
+  There are some special variables whose prefix depends on the number of
+  ``<module-spec>`` given.  When there is only one ``<module-spec>``,
+  ``<YYY>`` will simply be ``<prefix>``, but if two or more ``<module-spec>``
+  items are given, ``<YYY>`` will be ``<prefix>_<module-name>``.
+
+  ``<YYY>_VERSION``
+    The version of the module.
+  ``<YYY>_PREFIX``
+    The prefix directory of the module.
+  ``<YYY>_INCLUDEDIR``
+    The include directory of the module.
+  ``<YYY>_LIBDIR``
+    The lib directory of the module.
+
+  .. versionchanged:: 3.8
+    For any given ``<prefix>``, ``pkg_check_modules()`` can be called multiple
+    times with different parameters.  Previous versions of CMake cached and
+    returned the first successful result.
+
+  .. versionchanged:: 3.16
+    If a full path to the found library can't be determined, but it's still
+    visible to the linker, pass it through as ``-l<name>``.  Previous versions
+    of CMake failed in this case.
+
+.. command:: pkg_search_module
+
+  Searches for the first successful match from one or more provided module
+  specifications:
+
+  .. code-block:: cmake
+
+    pkg_search_module(
+      <prefix>
+      [QUIET]
+      [REQUIRED]
+      [NO_CMAKE_PATH]
+      [NO_CMAKE_ENVIRONMENT_PATH]
+      [IMPORTED_TARGET [GLOBAL]]
+      <module-spec> [<module-spec>...]
+    )
+
+  The behavior and arguments of this command are the same as
+  :command:`pkg_check_modules`, except that rather than checking for all
+  the specified modules, it searches for just the first successful match.
+
+  This command can be used, for example, when some package is known to have
+  possible multiple ``<module-spec>`` on different platforms or versions for
+  the same package.
+
+  .. rubric:: Result Variables
+
+  This command defines the same variables as described above with addition
+  to:
+
+  ``<prefix>_MODULE_NAME``
+    .. versionadded:: 3.16
+
+    If a module is found, the ``<prefix>_MODULE_NAME`` variable will contain
+    the name of the matching module. This variable can be used if the
+    :command:`pkg_get_variable` command needs to be called with the
+    ``<module-name>`` argument that was found by the
+    :command:`pkg_search_module`.
+
+.. command:: pkg_get_variable
+
+  .. versionadded:: 3.4
+
+  Retrieves the value of a ``pkg-config`` variable and stores it in the
+  result variable in the calling scope:
+
+  .. code-block:: cmake
+
+    pkg_get_variable(
+      <result-var>
+      <module-name>
+      <var-name>
+      [DEFINE_VARIABLES <key>=<value>...]
+    )
+
+  .. rubric:: The arguments are:
+
+  ``<result-var>``
+    Name of the result variable that will contain the value of ``pkg-config``
+    variable.  If ``pkg-config`` returns multiple values for the specified
+    variable ``<var-name>``, ``<result-var>`` will contain a
+    :ref:`semicolon-separated list <CMake Language Lists>`.
+
+  ``<module-name>``
+    Name of the module as defined in its PC metadata file name
+    (``<module-name>.pc``).
+
+  ``<var-name>``
+    The ``pkg-config`` variable name from the PC metadata file
+    ``<module-name>.pc``.
+
+  ``DEFINE_VARIABLES <key>=<value>...``
+    .. versionadded:: 3.28
+
+    Specify key-value pairs to redefine variables affecting the variable
+    retrieved with ``pkg-config``.
+
+Hints
+^^^^^
+
+This module accepts the following variables before calling
+``find_package(PkgConfig)`` to influence this module's behavior:
+
+``ENV{PKG_CONFIG_PATH}``
+  Environment variable that specifies additional paths in which
+  ``pkg-config`` will search for its ``.pc`` files.  The ``pkg-config``
+  tool by default uses this variable, while CMake also provides more common
+  :variable:`CMAKE_PREFIX_PATH` variable to specify additional paths where
+  to look for packages and their ``.pc`` files.
+
+``ENV{PKG_CONFIG}``
+  .. versionadded:: 3.1
+
+  Environment variable that can be set to the path of the ``pkg-config``
+  executable and can be used to initialize the ``PKG_CONFIG_EXECUTABLE``
+  variable, if it has not yet been set.
+
+``PKG_CONFIG_EXECUTABLE``
+
+  This cache variable can be set to the path of the ``pkg-config``
+  executable.  :command:`find_program` is called internally by the module
+  with this variable.
+
+  .. versionchanged:: 3.22
+    If the ``PKG_CONFIG`` environment variable is set, only the first
+    argument is taken from it when using it as a hint.
+
+``PKG_CONFIG_ARGN``
+
+  .. versionadded:: 3.22
+
+  This cache variable can be set to a list of arguments to additionally pass
+  to ``pkg-config`` if needed. If not provided, it will be initialized from
+  the ``PKG_CONFIG`` environment variable, if set. The first argument in that
+  environment variable is assumed to be the ``pkg-config`` program, while all
+  remaining arguments after that are used to initialize ``PKG_CONFIG_ARGN``.
+  If no such environment variable is defined, ``PKG_CONFIG_ARGN`` is
+  initialized to an empty string. The module does not update the variable once
+  it has been set in the cache.
+
+``PKG_CONFIG_USE_CMAKE_PREFIX_PATH``
+
+  .. versionadded:: 3.1
+
+  Specifies whether :command:`pkg_check_modules` and
+  :command:`pkg_search_module` should add the paths in the
+  :variable:`CMAKE_PREFIX_PATH`, :variable:`CMAKE_FRAMEWORK_PATH` and
+  :variable:`CMAKE_APPBUNDLE_PATH` cache and environment variables to the
+  ``pkg-config`` search path.
+
+  If this variable is not set, this behavior is enabled by default if
+  :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` is 3.1 or later, disabled
+  otherwise.
+
+Examples
+^^^^^^^^
+
+Examples: Finding pkg-config
+""""""""""""""""""""""""""""
+
+Finding ``pkg-config``:
+
+.. code-block:: cmake
+
+  find_package(PkgConfig)
+
+Finding ``pkg-config`` and making it required (if not found, processing stops
+with an error message):
+
+.. code-block:: cmake
+
+  find_package(PkgConfig REQUIRED)
+
+Finding ``pkg-config`` quietly without printing status message as commonly
+used in find modules:
+
+.. code-block:: cmake
+
+  find_package(PkgConfig QUIET)
+
+Examples: Using ``pkg_check_modules()``
+"""""""""""""""""""""""""""""""""""""""
+
+Checking for any version of glib2.  If found, the output variable
+``GLIB2_VERSION`` will hold the actual version found:
+
+.. code-block:: cmake
+
+  find_package(PkgConfig QUIET)
+
+  if(PKG_CONFIG_FOUND)
+    pkg_check_modules(GLIB2 glib-2.0)
+  endif()
+
+The following example looks for at least version 2.10 of glib2.  If found,
+the output variable ``GLIB2_VERSION`` will hold the actual version found:
+
+.. code-block:: cmake
+
+  find_package(PkgConfig QUIET)
+
+  if(PKG_CONFIG_FOUND)
+    pkg_check_modules(GLIB2 glib-2.0>=2.10)
+  endif()
+
+The following example looks for both glib2-2.0 (at least version 2.10) and
+any version of gtk2+-2.0.  Only if both are found will ``FOO`` be considered
+found.  The ``FOO_glib-2.0_VERSION`` and ``FOO_gtk+-2.0_VERSION`` variables
+will be set to their respective found module versions.
+
+.. code-block:: cmake
+
+  find_package(PkgConfig QUIET)
+
+  if(PKG_CONFIG_FOUND)
+    pkg_check_modules(FOO glib-2.0>=2.10 gtk+-2.0)
+  endif()
+
+The following example requires any version of ``xrender``:
+
+.. code-block:: cmake
+
+  find_package(PkgConfig QUIET REQUIRED)
+  pkg_check_modules(XRENDER REQUIRED xrender)
+
+Example output variables set by a successful call::
+
+  XRENDER_LIBRARIES=Xrender;X11
+  XRENDER_STATIC_LIBRARIES=Xrender;X11;pthread;Xau;Xdmcp
+
+Example: Using ``pkg_search_module()``
+""""""""""""""""""""""""""""""""""""""
+
+Searching for LibXml2 package, which might be provided with different
+module specifications (``libxml-2.0`` or ``libxml2``):
+
+.. code-block:: cmake
+
+  find_package(PkgConfig QUIET)
+
+  if(PKG_CONFIG_FOUND)
+    pkg_search_module(BAR libxml-2.0 libxml2 libxml>=2)
+  endif()
+
+Example: Creating Imported Target
+"""""""""""""""""""""""""""""""""
+
+In the following example an imported target is created from the module
+specifications to use in the project directly without using a find module.
+These imported targets can be used, for example, in cases, where package is
+known to support ``pkg-config`` on all supported platforms:
+
+.. code-block:: cmake
+
+  find_package(PkgConfig QUIET REQUIRED)
+  pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk4>=4.14)
+  target_link_libraries(example PRIVATE PkgConfig::GTK)
+
+Example: Using ``pkg_get_variable()``
+"""""""""""""""""""""""""""""""""""""
+
+Retrieving the value of ``pkg-config`` variable ``girdir`` from the package
+Gobject:
+
+.. code-block:: cmake
+
+  find_package(PkgConfig QUIET)
+
+  if(PKG_CONFIG_FOUND)
+    pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir)
+  endif()
+
+  message(STATUS "${GI_GIRDIR}")
+
+See Also
+^^^^^^^^
+
+* The :command:`cmake_pkg_config` command for a modern and more advanced
+  way to work with ``pkg-config`` in CMake without requiring ``pkg-config``
+  executable to be installed.
+* :ref:`Find Modules` for details how to write a find module.
 #]========================================]
 
 ### Common stuff ####
@@ -703,161 +1129,6 @@
   endif()
 endmacro()
 
-
-#[========================================[.rst:
-.. command:: pkg_check_modules
-
-  Checks for all the given modules, setting a variety of result variables in
-  the calling scope.
-
-  .. code-block:: cmake
-
-    pkg_check_modules(<prefix>
-                      [REQUIRED] [QUIET]
-                      [NO_CMAKE_PATH]
-                      [NO_CMAKE_ENVIRONMENT_PATH]
-                      [IMPORTED_TARGET [GLOBAL]]
-                      <moduleSpec> [<moduleSpec>...])
-
-  When the ``REQUIRED`` argument is given, the command will fail with an error
-  if module(s) could not be found.
-
-  When the ``QUIET`` argument is given, no status messages will be printed.
-
-  .. versionadded:: 3.3
-    The :variable:`CMAKE_PREFIX_PATH`,
-    :variable:`CMAKE_FRAMEWORK_PATH`, and :variable:`CMAKE_APPBUNDLE_PATH` cache
-    and environment variables will be added to the ``pkg-config`` search path.
-    The ``NO_CMAKE_PATH`` and ``NO_CMAKE_ENVIRONMENT_PATH`` arguments
-    disable this behavior for the cache variables and environment variables
-    respectively.
-    The :variable:`PKG_CONFIG_USE_CMAKE_PREFIX_PATH` variable set to ``FALSE``
-    disables this behavior globally.
-
-    .. This was actually added in 3.1, but didn't work until 3.3.
-
-  .. versionadded:: 3.7
-    The ``IMPORTED_TARGET`` argument will create an imported target named
-    ``PkgConfig::<prefix>`` that can be passed directly as an argument to
-    :command:`target_link_libraries`.
-
-    .. This was actually added in 3.6, but didn't work until 3.7.
-
-  .. versionadded:: 3.13
-    The ``GLOBAL`` argument will make the
-    imported target available in global scope.
-
-  .. versionadded:: 3.15
-    Non-library linker options reported by ``pkg-config`` are stored in the
-    :prop_tgt:`INTERFACE_LINK_OPTIONS` target property.
-
-  .. versionchanged:: 3.18
-    Include directories specified with ``-isystem`` are stored in the
-    :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target property.  Previous
-    versions of CMake left them in the :prop_tgt:`INTERFACE_COMPILE_OPTIONS`
-    property.
-
-  Each ``<moduleSpec>`` can be either a bare module name or it can be a
-  module name with a version constraint (operators ``=``, ``<``, ``>``,
-  ``<=`` and ``>=`` are supported).  The following are examples for a module
-  named ``foo`` with various constraints:
-
-  - ``foo`` matches any version.
-  - ``foo<2`` only matches versions before 2.
-  - ``foo>=3.1`` matches any version from 3.1 or later.
-  - ``foo=1.2.3`` requires that foo must be exactly version 1.2.3.
-
-  The following variables may be set upon return.  Two sets of values exist:
-  One for the common case (``<XXX> = <prefix>``) and another for the
-  information ``pkg-config`` provides when called with the ``--static``
-  option (``<XXX> = <prefix>_STATIC``).
-
-  ``<XXX>_FOUND``
-    set to 1 if module(s) exist
-  ``<XXX>_LIBRARIES``
-    only the libraries (without the '-l')
-  ``<XXX>_LINK_LIBRARIES``
-    the libraries and their absolute paths
-  ``<XXX>_LIBRARY_DIRS``
-    the paths of the libraries (without the '-L')
-  ``<XXX>_LDFLAGS``
-    all required linker flags
-  ``<XXX>_LDFLAGS_OTHER``
-    all other linker flags
-  ``<XXX>_INCLUDE_DIRS``
-    the '-I' preprocessor flags (without the '-I')
-  ``<XXX>_CFLAGS``
-    all required cflags
-  ``<XXX>_CFLAGS_OTHER``
-    the other compiler flags
-
-  All but ``<XXX>_FOUND`` may be a :ref:`;-list <CMake Language Lists>` if the
-  associated variable returned from ``pkg-config`` has multiple values.
-
-  .. versionchanged:: 3.18
-    Include directories specified with ``-isystem`` are stored in the
-    ``<XXX>_INCLUDE_DIRS`` variable.  Previous versions of CMake left them
-    in ``<XXX>_CFLAGS_OTHER``.
-
-  There are some special variables whose prefix depends on the number of
-  ``<moduleSpec>`` given.  When there is only one ``<moduleSpec>``,
-  ``<YYY>`` will simply be ``<prefix>``, but if two or more ``<moduleSpec>``
-  items are given, ``<YYY>`` will be ``<prefix>_<moduleName>``.
-
-  ``<YYY>_VERSION``
-    version of the module
-  ``<YYY>_PREFIX``
-    prefix directory of the module
-  ``<YYY>_INCLUDEDIR``
-    include directory of the module
-  ``<YYY>_LIBDIR``
-    lib directory of the module
-
-  .. versionchanged:: 3.8
-    For any given ``<prefix>``, ``pkg_check_modules()`` can be called multiple
-    times with different parameters.  Previous versions of CMake cached and
-    returned the first successful result.
-
-  .. versionchanged:: 3.16
-    If a full path to the found library can't be determined, but it's still
-    visible to the linker, pass it through as ``-l<name>``.  Previous versions
-    of CMake failed in this case.
-
-  Examples:
-
-  .. code-block:: cmake
-
-    pkg_check_modules (GLIB2 glib-2.0)
-
-  Looks for any version of glib2.  If found, the output variable
-  ``GLIB2_VERSION`` will hold the actual version found.
-
-  .. code-block:: cmake
-
-    pkg_check_modules (GLIB2 glib-2.0>=2.10)
-
-  Looks for at least version 2.10 of glib2.  If found, the output variable
-  ``GLIB2_VERSION`` will hold the actual version found.
-
-  .. code-block:: cmake
-
-    pkg_check_modules (FOO glib-2.0>=2.10 gtk+-2.0)
-
-  Looks for both glib2-2.0 (at least version 2.10) and any version of
-  gtk2+-2.0.  Only if both are found will ``FOO`` be considered found.
-  The ``FOO_glib-2.0_VERSION`` and ``FOO_gtk+-2.0_VERSION`` variables will be
-  set to their respective found module versions.
-
-  .. code-block:: cmake
-
-    pkg_check_modules (XRENDER REQUIRED xrender)
-
-  Requires any version of ``xrender``.  Example output variables set by a
-  successful call::
-
-    XRENDER_LIBRARIES=Xrender;X11
-    XRENDER_STATIC_LIBRARIES=Xrender;X11;pthread;Xau;Xdmcp
-#]========================================]
 macro(pkg_check_modules _prefix _module0)
   _pkgconfig_parse_options(_pkg_modules _pkg_is_required _pkg_is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global "${_module0}" ${ARGN})
   # check cached value
@@ -877,34 +1148,6 @@
   endif()
 endmacro()
 
-
-#[========================================[.rst:
-.. command:: pkg_search_module
-
-  The behavior of this command is the same as :command:`pkg_check_modules`,
-  except that rather than checking for all the specified modules, it searches
-  for just the first successful match.
-
-  .. code-block:: cmake
-
-    pkg_search_module(<prefix>
-                      [REQUIRED] [QUIET]
-                      [NO_CMAKE_PATH]
-                      [NO_CMAKE_ENVIRONMENT_PATH]
-                      [IMPORTED_TARGET [GLOBAL]]
-                      <moduleSpec> [<moduleSpec>...])
-
-  .. versionadded:: 3.16
-    If a module is found, the ``<prefix>_MODULE_NAME`` variable will contain the
-    name of the matching module. This variable can be used if you need to run
-    :command:`pkg_get_variable`.
-
-  Example:
-
-  .. code-block:: cmake
-
-    pkg_search_module (BAR libxml-2.0 libxml2 libxml>=2)
-#]========================================]
 macro(pkg_search_module _prefix _module0)
   _pkgconfig_parse_options(_pkg_modules_alt _pkg_is_required _pkg_is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global "${_module0}" ${ARGN})
   # check cached value
@@ -939,36 +1182,6 @@
   endif()
 endmacro()
 
-#[========================================[.rst:
-.. command:: pkg_get_variable
-
-  .. versionadded:: 3.4
-
-  Retrieves the value of a pkg-config variable ``varName`` and stores it in the
-  result variable ``resultVar`` in the calling scope.
-
-  .. code-block:: cmake
-
-    pkg_get_variable(<resultVar> <moduleName> <varName>
-                     [DEFINE_VARIABLES <key>=<value>...])
-
-  If ``pkg-config`` returns multiple values for the specified variable,
-  ``resultVar`` will contain a :ref:`;-list <CMake Language Lists>`.
-
-  Options:
-
-  ``DEFINE_VARIABLES <key>=<value>...``
-    .. versionadded:: 3.28
-
-    Specify key-value pairs to redefine variables affecting the variable
-    retrieved with ``pkg-config``.
-
-  For example:
-
-  .. code-block:: cmake
-
-    pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir)
-#]========================================]
 function (pkg_get_variable result pkg variable)
   set(_multiValueArgs DEFINE_VARIABLES)
 
@@ -989,55 +1202,3 @@
     PARENT_SCOPE)
   _pkg_restore_path_internal()
 endfunction ()
-
-
-#[========================================[.rst:
-Variables Affecting Behavior
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. variable:: PKG_CONFIG_EXECUTABLE
-
-  This cache variable can be set to the path of the pkg-config executable.
-  :command:`find_program` is called internally by the module with this
-  variable.
-
-  .. versionadded:: 3.1
-    The ``PKG_CONFIG`` environment variable can be used as a hint if
-    ``PKG_CONFIG_EXECUTABLE`` has not yet been set.
-
-  .. versionchanged:: 3.22
-    If the ``PKG_CONFIG`` environment variable is set, only the first
-    argument is taken from it when using it as a hint.
-
-.. variable:: PKG_CONFIG_ARGN
-
-  .. versionadded:: 3.22
-
-  This cache variable can be set to a list of arguments to additionally pass
-  to pkg-config if needed. If not provided, it will be initialized from the
-  ``PKG_CONFIG`` environment variable, if set. The first argument in that
-  environment variable is assumed to be the pkg-config program, while all
-  remaining arguments after that are used to initialize ``PKG_CONFIG_ARGN``.
-  If no such environment variable is defined, ``PKG_CONFIG_ARGN`` is
-  initialized to an empty string. The module does not update the variable once
-  it has been set in the cache.
-
-.. variable:: PKG_CONFIG_USE_CMAKE_PREFIX_PATH
-
-  .. versionadded:: 3.1
-
-  Specifies whether :command:`pkg_check_modules` and
-  :command:`pkg_search_module` should add the paths in the
-  :variable:`CMAKE_PREFIX_PATH`, :variable:`CMAKE_FRAMEWORK_PATH` and
-  :variable:`CMAKE_APPBUNDLE_PATH` cache and environment variables to the
-  ``pkg-config`` search path.
-
-  If this variable is not set, this behavior is enabled by default if
-  :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` is 3.1 or later, disabled
-  otherwise.
-#]========================================]
-
-
-### Local Variables:
-### mode: cmake
-### End:
diff --git a/Modules/FindPostgreSQL.cmake b/Modules/FindPostgreSQL.cmake
index ede8f0d..11368d3 100644
--- a/Modules/FindPostgreSQL.cmake
+++ b/Modules/FindPostgreSQL.cmake
@@ -6,7 +6,11 @@
 --------------
 
 Finds the PostgreSQL installation - the client library (``libpq``) and
-optionally the server.
+optionally the server:
+
+.. code-block:: cmake
+
+  find_package(PostgreSQL [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -28,14 +32,21 @@
 ``PostgreSQL_FOUND``
   Boolean indicating whether the minimum required version and components of
   PostgreSQL have been found.
+
+``PostgreSQL_VERSION``
+  .. versionadded:: 4.2
+
+  The version of PostgreSQL found.
+
 ``PostgreSQL_LIBRARIES``
   The PostgreSQL libraries needed for linking.
+
 ``PostgreSQL_INCLUDE_DIRS``
   The include directories containing PostgreSQL headers.
+
 ``PostgreSQL_LIBRARY_DIRS``
   The directories containing PostgreSQL libraries.
-``PostgreSQL_VERSION_STRING``
-  The version of PostgreSQL found.
+
 ``PostgreSQL_TYPE_INCLUDE_DIR``
   The include directory containing PostgreSQL server headers.
 
@@ -51,6 +62,17 @@
   ``PostgreSQL_TYPE_INCLUDE_DIR`` variable is set regardless of whether this
   component is specified in the ``find_package()`` call.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``PostgreSQL_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``PostgreSQL_VERSION``.
+
+  The version of PostgreSQL found.
+
 Examples
 ^^^^^^^^
 
@@ -288,14 +310,16 @@
       math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000")
       math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000 / 100")
       math(EXPR _PostgreSQL_patch_version "${_PostgreSQL_VERSION_NUM} % 100")
-      set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}.${_PostgreSQL_patch_version}")
+      set(PostgreSQL_VERSION "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}.${_PostgreSQL_patch_version}")
+      set(PostgreSQL_VERSION_STRING "${PostgreSQL_VERSION}")
       unset(_PostgreSQL_major_version)
       unset(_PostgreSQL_minor_version)
       unset(_PostgreSQL_patch_version)
     else ()
       math(EXPR _PostgreSQL_major_version "${_PostgreSQL_VERSION_NUM} / 10000")
       math(EXPR _PostgreSQL_minor_version "${_PostgreSQL_VERSION_NUM} % 10000")
-      set(PostgreSQL_VERSION_STRING "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}")
+      set(PostgreSQL_VERSION "${_PostgreSQL_major_version}.${_PostgreSQL_minor_version}")
+      set(PostgreSQL_VERSION_STRING "${PostgreSQL_VERSION}")
       unset(_PostgreSQL_major_version)
       unset(_PostgreSQL_minor_version)
     endif ()
@@ -306,7 +330,8 @@
              REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"")
         if(pgsql_version_str)
           string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*"
-                 "\\1" PostgreSQL_VERSION_STRING "${pgsql_version_str}")
+                 "\\1" PostgreSQL_VERSION "${pgsql_version_str}")
+          set(PostgreSQL_VERSION_STRING "${PostgreSQL_VERSION}")
           break()
         endif()
       endif()
@@ -328,7 +353,7 @@
 find_package_handle_standard_args(PostgreSQL
                                   REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR
                                   HANDLE_COMPONENTS
-                                  VERSION_VAR PostgreSQL_VERSION_STRING)
+                                  VERSION_VAR PostgreSQL_VERSION)
 
 function(__postgresql_import_library _target _var _config)
   if(_config)
diff --git a/Modules/FindProducer.cmake b/Modules/FindProducer.cmake
index 1d034bc..1769cdd 100644
--- a/Modules/FindProducer.cmake
+++ b/Modules/FindProducer.cmake
@@ -15,7 +15,11 @@
   OpenSceneGraph usage, refer to the :module:`FindOpenSceneGraph` module.
 
 This module finds the Producer library, a windowing and event handling library
-designed primarily for real-time graphics applications.
+designed primarily for real-time graphics applications:
+
+.. code-block:: cmake
+
+  find_package(Producer [...])
 
 Producer library headers are intended to be included in C++ project source code
 as:
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 28f47b4..8a739af 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -87,7 +87,7 @@
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets <Imported Targets>`:
+This module provides the following :ref:`Imported Targets`:
 
 .. versionchanged:: 3.14
   :ref:`Imported Targets <Imported Targets>` are only created when
@@ -138,7 +138,7 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module will set the following variables in your project
+This module defines the following variables
 (see :ref:`Standard Variable Names <CMake Developer Standard Variable Names>`):
 
 ``Python_FOUND``
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index 869dc70..535f0be 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -81,7 +81,7 @@
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets <Imported Targets>`:
+This module provides the following :ref:`Imported Targets`:
 
 .. versionchanged:: 3.14
   :ref:`Imported Targets <Imported Targets>` are only created when
@@ -125,7 +125,7 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module will set the following variables in your project
+This module defines the following variables
 (see :ref:`Standard Variable Names <CMake Developer Standard Variable Names>`):
 
 ``Python2_FOUND``
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index 66c325a..84f2d42 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -89,7 +89,7 @@
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets <Imported Targets>`:
+This module provides the following :ref:`Imported Targets`:
 
 .. versionchanged:: 3.14
   :ref:`Imported Targets <Imported Targets>` are only created when
@@ -140,7 +140,7 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module will set the following variables in your project
+This module defines the following variables
 (see :ref:`Standard Variable Names <CMake Developer Standard Variable Names>`):
 
 ``Python3_FOUND``
diff --git a/Modules/FindQt.cmake b/Modules/FindQt.cmake
index 98cd1e2..efe5349 100644
--- a/Modules/FindQt.cmake
+++ b/Modules/FindQt.cmake
@@ -31,7 +31,7 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``QT4_INSTALLED``
   ``TRUE`` if Qt4 is found.
diff --git a/Modules/FindQt3.cmake b/Modules/FindQt3.cmake
index 2c62a5f..ae4bb93 100644
--- a/Modules/FindQt3.cmake
+++ b/Modules/FindQt3.cmake
@@ -5,8 +5,12 @@
 FindQt3
 -------
 
-This module finds Qt3, a cross-platform application development framework for
-creating graphical user interfaces and applications.
+Finds Qt3, a cross-platform application development framework for creating
+graphical user interfaces and applications:
+
+.. code-block:: cmake
+
+  find_package(Qt3 [<version>] [...])
 
 .. note::
 
@@ -17,13 +21,13 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``Qt3_FOUND``
-  True if Qt3 has been found.
+  Boolean indicating whether Qt3 has been found.
 ``QT_FOUND``
-  True if Qt3 has been found.  This variable is for compatibility with other Qt
-  find modules.
+  Boolean indicating whether Qt3 has been found.  This variable is for
+  compatibility with other Qt find modules.
 ``QT_VERSION_STRING``
   The version of Qt3 that was found.
 ``QT_LIBRARIES``
@@ -88,7 +92,7 @@
 #  QT_WRAP_UI set true if QT_UIC_EXECUTABLE is found
 
 # If Qt4 has already been found, fail.
-if(QT4_FOUND)
+if(Qt4_FOUND)
   if(Qt3_FIND_REQUIRED)
     message( FATAL_ERROR "Qt3 and Qt4 cannot be used together in one project.")
   else()
diff --git a/Modules/FindQt4.cmake b/Modules/FindQt4.cmake
index 2c9e39f..c084e81 100644
--- a/Modules/FindQt4.cmake
+++ b/Modules/FindQt4.cmake
@@ -5,9 +5,15 @@
 FindQt4
 -------
 
-This module finds Qt4, a cross-platform application development framework for
-creating graphical user interfaces and applications.  It defines a number of
-imported targets, macros, and variables to use Qt4 in the project.
+Finds Qt4, a cross-platform application development framework for creating
+graphical user interfaces and applications:
+
+.. code-block:: cmake
+
+  find_package(Qt4 [<version>] [...])
+
+This module defines a number of imported targets, macros, and variables to
+use Qt4 in the project.
 
 .. note::
 
@@ -39,7 +45,7 @@
 ^^^^^^^^^^^^^^^^
 
 Qt libraries can be linked using their corresponding
-:ref:`IMPORTED target <Imported Targets>` with the
+:ref:`Imported Target <Imported Targets>` with the
 :command:`target_link_libraries` command:
 
 .. code-block:: cmake
@@ -118,20 +124,21 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
 
 ``Qt4_FOUND``
-  Boolean whether Qt4 has been found.  If false, don't try to use Qt4.
+  Boolean indicating whether (the requested version of) Qt4 is found.
+
 ``QT_FOUND``
-  Boolean whether Qt4 has been found.  If false, don't try to use Qt4.  This
-  variable is for compatibility with other Qt find modules.
-``QT4_FOUND``
-  Boolean whether Qt4 has been found.  If false, don't try to use Qt4.  This
-  variable is for backward compatibility only.
+  Boolean indicating whether (the requested version of) Qt4 has been found.
+  This variable is available for compatibility with other Qt find modules.
+
 ``QT_VERSION_MAJOR``
   The major version of Qt found.
+
 ``QT_VERSION_MINOR``
   The minor version of Qt found.
+
 ``QT_VERSION_PATCH``
   The patch version of Qt found.
 
@@ -432,6 +439,15 @@
   the ``QtCore``, ``QtGui`` and ``QtDeclarative`` components on the project
   target ``myexe``.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``QT4_FOUND``
+  .. deprecated:: 2.8.11
+    Use ``Qt4_FOUND``, which has the same value.
+
 Examples
 ^^^^^^^^
 
diff --git a/Modules/FindQuickTime.cmake b/Modules/FindQuickTime.cmake
index 3f6b5ee..55d98d3 100644
--- a/Modules/FindQuickTime.cmake
+++ b/Modules/FindQuickTime.cmake
@@ -6,7 +6,11 @@
 -------------
 
 Finds the QuickTime multimedia framework, which provides support for video,
-audio, and interactive media.
+audio, and interactive media:
+
+.. code-block:: cmake
+
+  find_package(QuickTime [...])
 
 .. note::
 
@@ -48,11 +52,24 @@
 Examples
 ^^^^^^^^
 
-Finding QuickTime library:
+Finding QuickTime library and creating an imported interface target for
+linking it to a project target:
 
 .. code-block:: cmake
 
   find_package(QuickTime)
+
+  if(QuickTime_FOUND AND NOT TARGET QuickTime::QuickTime)
+    add_library(QuickTime::QuickTime INTERFACE IMPORTED)
+    set_target_properties(
+      QuickTime::QuickTime
+      PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${QUICKTIME_INCLUDE_DIR}"
+        INTERFACE_LINK_LIBRARIES "${QUICKTIME_LIBRARY}"
+    )
+  endif()
+
+  target_link_libraries(example PRIVATE QuickTime::QuickTime)
 #]=======================================================================]
 
 find_path(QUICKTIME_INCLUDE_DIR QuickTime/QuickTime.h QuickTime.h
diff --git a/Modules/FindRTI.cmake b/Modules/FindRTI.cmake
index 6a1a024..87c97c3 100644
--- a/Modules/FindRTI.cmake
+++ b/Modules/FindRTI.cmake
@@ -5,7 +5,11 @@
 FindRTI
 -------
 
-Finds HLA RTI standard libraries and their include directories.
+Finds HLA RTI standard libraries and their include directories:
+
+.. code-block:: cmake
+
+  find_package(RTI [...])
 
 `RTI <https://en.wikipedia.org/wiki/Run-time_infrastructure_(simulation)>`_
 (Run-Time Infrastructure) is a simulation infrastructure standardized by IEEE
@@ -19,7 +23,7 @@
 This module defines the following variables:
 
 ``RTI_FOUND``
-  Set to FALSE if any HLA RTI was not found.
+  Boolean indicating whether HLA RTI is found.
 ``RTI_LIBRARIES``
   The libraries to link against to use RTI.
 ``RTI_DEFINITIONS``
@@ -37,11 +41,25 @@
 Examples
 ^^^^^^^^
 
-Finding RTI:
+Finding RTI and creating an imported interface target for linking it to a
+project target:
 
 .. code-block:: cmake
 
   find_package(RTI)
+
+  if(RTI_FOUND AND NOT TARGET RTI::RTI)
+    add_library(RTI::RTI INTERFACE IMPORTED)
+    set_target_properties(
+      RTI::RTI
+      PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${RTI_INCLUDE_DIR}"
+        INTERFACE_LINK_LIBRARIES "${RTI_LIBRARIES}"
+        INTERFACE_COMPILE_DEFINITIONS "${RTI_DEFINITIONS}"
+    )
+  endif()
+
+  target_link_libraries(example PRIVATE RTI::RTI)
 #]=======================================================================]
 
 macro(RTI_MESSAGE_QUIETLY QUIET TYPE MSG)
diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake
index 18b9e35..1667271 100644
--- a/Modules/FindRuby.cmake
+++ b/Modules/FindRuby.cmake
@@ -5,65 +5,55 @@
 FindRuby
 --------
 
-This module determines if Ruby is installed and finds the locations of its
-include files and libraries. Ruby 1.8 through 3.4 are supported.
-
-The minimum required version of Ruby can be specified using the
-standard syntax, e.g.
+Finds Ruby installation and the locations of its include files and libraries:
 
 .. code-block:: cmake
 
-  find_package(Ruby 3.2.6 EXACT REQUIRED)
-  # OR
-  find_package(Ruby 3.2)
+  find_package(Ruby [<version>] [...])
 
-Virtual environments, such as RVM or RBENV, are supported.
+Ruby is a general-purpose programming language.  This module supports Ruby
+1.8 through 3.4.  Virtual environments, such as RVM or RBENV, are also
+supported.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module will set the following variables in your project:
+This module defines the following variables:
 
 ``Ruby_FOUND``
-  set to true if ruby was found successfully
-``Ruby_EXECUTABLE``
-  full path to the ruby binary
-``Ruby_INCLUDE_DIRS``
-  include dirs to be used when using the ruby library
-``Ruby_LIBRARIES``
-  .. versionadded:: 3.18
-    libraries needed to use ruby from C.
+  Boolean indicating whether (the requested version of) ruby is found.
+
 ``Ruby_VERSION``
-  the version of ruby which was found, e.g. "3.2.6"
+  The version of ruby which was found, e.g. ``3.2.6``.
+
 ``Ruby_VERSION_MAJOR``
   Ruby major version.
+
 ``Ruby_VERSION_MINOR``
   Ruby minor version.
+
 ``Ruby_VERSION_PATCH``
   Ruby patch version.
 
+``Ruby_EXECUTABLE``
+  The full path to the ruby binary.
+
+``Ruby_INCLUDE_DIRS``
+  Include dirs to be used when using the ruby library.
+
+``Ruby_LIBRARIES``
+  .. versionadded:: 3.18
+
+  Libraries needed to use ruby from C.
+
 .. versionchanged:: 3.18
   Previous versions of CMake used the ``RUBY_`` prefix for all variables.
 
-.. deprecated:: 4.0
-  The following variables are deprecated.  See policy :policy:`CMP0185`.
-
-  ``RUBY_EXECUTABLE``
-    same as ``Ruby_EXECUTABLE``.
-  ``RUBY_INCLUDE_DIRS``
-    same as ``Ruby_INCLUDE_DIRS``.
-  ``RUBY_INCLUDE_PATH``
-    same as ``Ruby_INCLUDE_DIRS``.
-  ``RUBY_LIBRARY``
-    same as ``Ruby_LIBRARY``.
-  ``RUBY_VERSION``
-    same as ``Ruby_VERSION``.
-  ``RUBY_FOUND``
-    same as ``Ruby_FOUND``.
-
 Hints
 ^^^^^
 
+This module accepts the following variables:
+
 ``Ruby_FIND_VIRTUALENV``
   .. versionadded:: 3.18
 
@@ -84,6 +74,38 @@
   ``rbenv``
     Requires that ``rbenv`` is installed in ``~/.rbenv/bin``
     or that the ``RBENV_ROOT`` environment variable is defined.
+
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+.. deprecated:: 4.0
+  The following variables are deprecated.  See policy :policy:`CMP0185`.
+
+  ``RUBY_FOUND``
+    Same as ``Ruby_FOUND``.
+  ``RUBY_VERSION``
+    Same as ``Ruby_VERSION``.
+  ``RUBY_EXECUTABLE``
+    Same as ``Ruby_EXECUTABLE``.
+  ``RUBY_INCLUDE_DIRS``
+    Same as ``Ruby_INCLUDE_DIRS``.
+  ``RUBY_INCLUDE_PATH``
+    Same as ``Ruby_INCLUDE_DIRS``.
+  ``RUBY_LIBRARY``
+    Same as ``Ruby_LIBRARY``.
+
+Examples
+^^^^^^^^
+
+Finding Ruby and specifying the minimum required version:
+
+.. code-block:: cmake
+
+  find_package(Ruby 3.2.6 EXACT REQUIRED)
+  # or
+  find_package(Ruby 3.2)
 #]=======================================================================]
 
 cmake_policy(GET CMP0185 _Ruby_CMP0185)
diff --git a/Modules/FindSDL.cmake b/Modules/FindSDL.cmake
index a720dcc..a47e8c1 100644
--- a/Modules/FindSDL.cmake
+++ b/Modules/FindSDL.cmake
@@ -5,8 +5,14 @@
 FindSDL
 -------
 
-Finds the SDL (Simple DirectMedia Layer) library.  SDL is a cross-platform
-library for developing multimedia software, such as games and emulators.
+Finds the SDL (Simple DirectMedia Layer) library:
+
+.. code-block:: cmake
+
+  find_package(SDL [<version>] [...])
+
+SDL is a cross-platform library for developing multimedia software, such as
+games and emulators.
 
 .. note::
 
@@ -127,7 +133,7 @@
 Deprecated Variables
 ^^^^^^^^^^^^^^^^^^^^
 
-These variables are obsolete and provided for backwards compatibility:
+The following variables are provided for backward compatibility:
 
 ``SDL_VERSION_STRING``
   .. deprecated:: 3.19
@@ -288,7 +294,7 @@
 
 find_package_handle_standard_args(SDL
                                   REQUIRED_VARS SDL_LIBRARY SDL_INCLUDE_DIR
-                                  VERSION_VAR SDL_VERSION_STRING)
+                                  VERSION_VAR SDL_VERSION)
 
 if(SDL_FOUND)
   set(SDL_LIBRARIES ${SDL_LIBRARY})
diff --git a/Modules/FindSDL_gfx.cmake b/Modules/FindSDL_gfx.cmake
index c7f489e..e4cadc8 100644
--- a/Modules/FindSDL_gfx.cmake
+++ b/Modules/FindSDL_gfx.cmake
@@ -8,7 +8,11 @@
 .. versionadded:: 3.25
 
 Finds the SDL_gfx library that provides graphics support in SDL (Simple
-DirectMedia Layer) applications.
+DirectMedia Layer) applications:
+
+.. code-block:: cmake
+
+  find_package(SDL_gfx [<version>] [...])
 
 .. note::
 
@@ -30,10 +34,13 @@
 This module defines the following variables:
 
 ``SDL_gfx_FOUND``
-  Boolean indicating whether the (requested version of) SDL_gfx library is
+  Boolean indicating whether (the requested version of) SDL_gfx library is
   found.  For backward compatibility, the ``SDL_GFX_FOUND`` variable is also set
   to the same value.
-``SDL_GFX_VERSION_STRING``
+
+``SDL_gfx_VERSION``
+  .. versionadded:: 4.2
+
   The human-readable string containing the version of SDL_gfx found.
 
 Cache Variables
@@ -43,6 +50,7 @@
 
 ``SDL_GFX_INCLUDE_DIRS``
   The directory containing the headers needed to use SDL_gfx.
+
 ``SDL_GFX_LIBRARIES``
   The path to the SDL_gfx library needed to link against to use SDL_gfx.
 
@@ -57,6 +65,17 @@
   was used when configuring, building, and installing SDL library:
   ``./configure --prefix=$SDLDIR``.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``SDL_GFX_VERSION_STRING``
+  .. deprecated:: 4.2
+    Use the ``SDL_gfx_VERSION``.
+
+  The human-readable string containing the version of SDL_gfx found.
+
 Examples
 ^^^^^^^^
 
@@ -113,7 +132,8 @@
   string(REGEX REPLACE "^#define[ \t]+SDL_GFXPRIMITIVES_MAJOR[ \t]+([0-9]+)$" "\\1" SDL_GFX_VERSION_MAJOR "${SDL_GFX_VERSION_MAJOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_GFXPRIMITIVES_MINOR[ \t]+([0-9]+)$" "\\1" SDL_GFX_VERSION_MINOR "${SDL_GFX_VERSION_MINOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_GFXPRIMITIVES_MICRO[ \t]+([0-9]+)$" "\\1" SDL_GFX_VERSION_PATCH "${SDL_GFX_VERSION_PATCH_LINE}")
-  set(SDL_GFX_VERSION_STRING ${SDL_GFX_VERSION_MAJOR}.${SDL_GFX_VERSION_MINOR}.${SDL_GFX_VERSION_PATCH})
+  set(SDL_gfx_VERSION ${SDL_GFX_VERSION_MAJOR}.${SDL_GFX_VERSION_MINOR}.${SDL_GFX_VERSION_PATCH})
+  set(SDL_GFX_VERSION_STRING "${SDL_gfx_VERSION}")
   unset(SDL_GFX_VERSION_MAJOR_LINE)
   unset(SDL_GFX_VERSION_MINOR_LINE)
   unset(SDL_GFX_VERSION_PATCH_LINE)
@@ -126,7 +146,7 @@
 
 find_package_handle_standard_args(SDL_gfx
                                   REQUIRED_VARS SDL_GFX_LIBRARIES SDL_GFX_INCLUDE_DIRS
-                                  VERSION_VAR SDL_GFX_VERSION_STRING)
+                                  VERSION_VAR SDL_gfx_VERSION)
 
 if(SDL_gfx_FOUND)
   if(NOT TARGET SDL::SDL_gfx)
diff --git a/Modules/FindSDL_image.cmake b/Modules/FindSDL_image.cmake
index 5835532..395c128 100644
--- a/Modules/FindSDL_image.cmake
+++ b/Modules/FindSDL_image.cmake
@@ -6,7 +6,11 @@
 -------------
 
 Finds the SDL_image library that loads images of various formats as SDL (Simple
-DirectMedia Layer) surfaces.
+DirectMedia Layer) surfaces:
+
+.. code-block:: cmake
+
+  find_package(SDL_image [<version>] [...])
 
 .. note::
 
@@ -27,7 +31,9 @@
   found.  For backward compatibility, the ``SDL_IMAGE_FOUND`` variable is also
   set to the same value.
 
-``SDL_IMAGE_VERSION_STRING``
+``SDL_image_VERSION``
+  .. versionadded:: 4.2
+
   The human-readable string containing the version of SDL_image found.
 
 ``SDL_IMAGE_INCLUDE_DIRS``
@@ -50,7 +56,13 @@
 Deprecated Variables
 ^^^^^^^^^^^^^^^^^^^^
 
-For backward compatibility the following variables are also set:
+The following variables are provided for backward compatibility:
+
+``SDL_IMAGE_VERSION_STRING``
+  .. deprecated:: 4.2
+    Use the ``SDL_image_VERSION``.
+
+  The human-readable string containing the version of SDL_image found.
 
 ``SDLIMAGE_FOUND``
   .. deprecated:: 2.8.10
@@ -149,7 +161,8 @@
   string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_IMAGE_VERSION_MAJOR "${SDL_IMAGE_VERSION_MAJOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_IMAGE_VERSION_MINOR "${SDL_IMAGE_VERSION_MINOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_IMAGE_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_IMAGE_VERSION_PATCH "${SDL_IMAGE_VERSION_PATCH_LINE}")
-  set(SDL_IMAGE_VERSION_STRING ${SDL_IMAGE_VERSION_MAJOR}.${SDL_IMAGE_VERSION_MINOR}.${SDL_IMAGE_VERSION_PATCH})
+  set(SDL_image_VERSION ${SDL_IMAGE_VERSION_MAJOR}.${SDL_IMAGE_VERSION_MINOR}.${SDL_IMAGE_VERSION_PATCH})
+  set(SDL_IMAGE_VERSION_STRING "${SDL_image_VERSION}")
   unset(SDL_IMAGE_VERSION_MAJOR_LINE)
   unset(SDL_IMAGE_VERSION_MINOR_LINE)
   unset(SDL_IMAGE_VERSION_PATCH_LINE)
@@ -165,7 +178,7 @@
 
 find_package_handle_standard_args(SDL_image
                                   REQUIRED_VARS SDL_IMAGE_LIBRARIES SDL_IMAGE_INCLUDE_DIRS
-                                  VERSION_VAR SDL_IMAGE_VERSION_STRING)
+                                  VERSION_VAR SDL_image_VERSION)
 
 # for backward compatibility
 set(SDLIMAGE_LIBRARY ${SDL_IMAGE_LIBRARIES})
diff --git a/Modules/FindSDL_mixer.cmake b/Modules/FindSDL_mixer.cmake
index a9bafbc..00dbb17 100644
--- a/Modules/FindSDL_mixer.cmake
+++ b/Modules/FindSDL_mixer.cmake
@@ -6,7 +6,11 @@
 -------------
 
 Finds the SDL_mixer library that provides an audio mixer with support for
-various file formats in SDL (Simple DirectMedia Layer) applications.
+various file formats in SDL (Simple DirectMedia Layer) applications:
+
+.. code-block:: cmake
+
+  find_package(SDL_mixer [<version>] [...])
 
 .. note::
 
@@ -26,7 +30,9 @@
   found.  For backward compatibility, the ``SDL_MIXER_FOUND`` variable is also
   set to the same value.
 
-``SDL_MIXER_VERSION_STRING``
+``SDL_mixer_VERSION``
+  .. versionadded:: 4.2
+
   The human-readable string containing the version of SDL_mixer found.
 
 ``SDL_MIXER_INCLUDE_DIRS``
@@ -49,7 +55,13 @@
 Deprecated Variables
 ^^^^^^^^^^^^^^^^^^^^
 
-For backward compatibility the following variables are also set:
+The following variables are provided for backward compatibility:
+
+``SDL_MIXER_VERSION_STRING``
+  .. deprecated:: 4.2
+    Use the ``SDL_mixer_VERSION``.
+
+  The human-readable string containing the version of SDL_mixer found.
 
 ``SDLMIXER_FOUND``
   .. deprecated:: 2.8.10
@@ -141,7 +153,8 @@
   string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_MAJOR "${SDL_MIXER_VERSION_MAJOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_MINOR "${SDL_MIXER_VERSION_MINOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_MIXER_VERSION_PATCH "${SDL_MIXER_VERSION_PATCH_LINE}")
-  set(SDL_MIXER_VERSION_STRING ${SDL_MIXER_VERSION_MAJOR}.${SDL_MIXER_VERSION_MINOR}.${SDL_MIXER_VERSION_PATCH})
+  set(SDL_mixer_VERSION ${SDL_MIXER_VERSION_MAJOR}.${SDL_MIXER_VERSION_MINOR}.${SDL_MIXER_VERSION_PATCH})
+  set(SDL_MIXER_VERSION_STRING "${SDL_mixer_VERSION}")
   unset(SDL_MIXER_VERSION_MAJOR_LINE)
   unset(SDL_MIXER_VERSION_MINOR_LINE)
   unset(SDL_MIXER_VERSION_PATCH_LINE)
@@ -157,7 +170,7 @@
 
 find_package_handle_standard_args(SDL_mixer
                                   REQUIRED_VARS SDL_MIXER_LIBRARIES SDL_MIXER_INCLUDE_DIRS
-                                  VERSION_VAR SDL_MIXER_VERSION_STRING)
+                                  VERSION_VAR SDL_mixer_VERSION)
 
 # for backward compatibility
 set(SDLMIXER_LIBRARY ${SDL_MIXER_LIBRARIES})
diff --git a/Modules/FindSDL_net.cmake b/Modules/FindSDL_net.cmake
index c5ba976..5d36945 100644
--- a/Modules/FindSDL_net.cmake
+++ b/Modules/FindSDL_net.cmake
@@ -6,7 +6,11 @@
 -----------
 
 Finds the SDL_net library, a cross-platform network library for use with the
-SDL (Simple DirectMedia Layer) applications.
+SDL (Simple DirectMedia Layer) applications:
+
+.. code-block:: cmake
+
+  find_package(SDL_net [<version>] [...])
 
 .. note::
 
@@ -26,7 +30,9 @@
   found.  For backward compatibility, the ``SDL_NET_FOUND`` variable is also set
   to the same value.
 
-``SDL_NET_VERSION_STRING``
+``SDL_net_VERSION``
+  ..versionadded:: 4.2
+
   The human-readable string containing the version of SDL_net found.
 
 ``SDL_NET_INCLUDE_DIRS``
@@ -35,10 +41,27 @@
 ``SDL_NET_LIBRARIES``
   Libraries needed to link against to use the SDL_net library.
 
+Hints
+^^^^^
+
+This module accepts the following variables:
+
+``SDLDIR``
+  Environment variable that can be set to help locate an SDL library installed
+  in a custom location.  It should point to the installation destination that
+  was used when configuring, building, and installing SDL library:
+  ``./configure --prefix=$SDLDIR``.
+
 Deprecated Variables
 ^^^^^^^^^^^^^^^^^^^^
 
-For backward compatibility the following variables are also set:
+The following variables are provided for backward compatibility:
+
+``SDL_NET_VERSION_STRING``
+  .. deprecated:: 4.2
+    Use the ``SDL_net_VERSION``.
+
+  The human-readable string containing the version of SDL_net found.
 
 ``SDLNET_FOUND``
   .. deprecated:: 2.8.10
@@ -52,17 +75,6 @@
   .. deprecated:: 2.8.10
     Use the ``SDL_NET_LIBRARIES``, which has the same value.
 
-Hints
-^^^^^
-
-This module accepts the following variables:
-
-``SDLDIR``
-  Environment variable that can be set to help locate an SDL library installed
-  in a custom location.  It should point to the installation destination that
-  was used when configuring, building, and installing SDL library:
-  ``./configure --prefix=$SDLDIR``.
-
 Examples
 ^^^^^^^^
 
@@ -141,7 +153,8 @@
   string(REGEX REPLACE "^#define[ \t]+SDL_NET_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_NET_VERSION_MAJOR "${SDL_NET_VERSION_MAJOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_NET_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_NET_VERSION_MINOR "${SDL_NET_VERSION_MINOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_NET_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_NET_VERSION_PATCH "${SDL_NET_VERSION_PATCH_LINE}")
-  set(SDL_NET_VERSION_STRING ${SDL_NET_VERSION_MAJOR}.${SDL_NET_VERSION_MINOR}.${SDL_NET_VERSION_PATCH})
+  set(SDL_net_VERSION ${SDL_NET_VERSION_MAJOR}.${SDL_NET_VERSION_MINOR}.${SDL_NET_VERSION_PATCH})
+  set(SDL_NET_VERSION_STRING "${SDL_net_VERSION}")
   unset(SDL_NET_VERSION_MAJOR_LINE)
   unset(SDL_NET_VERSION_MINOR_LINE)
   unset(SDL_NET_VERSION_PATCH_LINE)
@@ -157,7 +170,7 @@
 
 find_package_handle_standard_args(SDL_net
                                   REQUIRED_VARS SDL_NET_LIBRARIES SDL_NET_INCLUDE_DIRS
-                                  VERSION_VAR SDL_NET_VERSION_STRING)
+                                  VERSION_VAR SDL_net_VERSION)
 
 # for backward compatibility
 set(SDLNET_LIBRARY ${SDL_NET_LIBRARIES})
diff --git a/Modules/FindSDL_sound.cmake b/Modules/FindSDL_sound.cmake
index 954303f..03f20b2 100644
--- a/Modules/FindSDL_sound.cmake
+++ b/Modules/FindSDL_sound.cmake
@@ -6,7 +6,11 @@
 -------------
 
 Finds the SDL_sound library, an abstract soundfile decoder for use in SDL
-(Simple DirectMedia Layer) applications.
+(Simple DirectMedia Layer) applications:
+
+.. code-block:: cmake
+
+  find_package(SDL_sound [<version>] [...])
 
 .. note::
 
@@ -35,7 +39,9 @@
   found.  For backward compatibility, the ``SDL_SOUND_FOUND`` variable is also
   set to the same value.
 
-``SDL_SOUND_VERSION_STRING``
+``SDL_sound_VERSION``
+  .. versionadded:: 4.2
+
   The human-readable string containing the version of SDL_sound found.
 
 ``SDL_SOUND_LIBRARIES``
@@ -100,6 +106,17 @@
   available mostly for cases this module failed to anticipate for and additional
   flags must be added.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``SDL_SOUND_VERSION_STRING``
+  .. deprecated:: 4.2
+    Use the ``SDL_sound_VERSION``.
+
+  The human-readable string containing the version of SDL_sound found.
+
 Examples
 ^^^^^^^^
 
@@ -441,7 +458,8 @@
   string(REGEX REPLACE "^#define[ \t]+SOUND_VER_MAJOR[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_MAJOR "${SDL_SOUND_VERSION_MAJOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SOUND_VER_MINOR[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_MINOR "${SDL_SOUND_VERSION_MINOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SOUND_VER_PATCH[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_PATCH "${SDL_SOUND_VERSION_PATCH_LINE}")
-  set(SDL_SOUND_VERSION_STRING ${SDL_SOUND_VERSION_MAJOR}.${SDL_SOUND_VERSION_MINOR}.${SDL_SOUND_VERSION_PATCH})
+  set(SDL_sound_VERSION ${SDL_SOUND_VERSION_MAJOR}.${SDL_SOUND_VERSION_MINOR}.${SDL_SOUND_VERSION_PATCH})
+  set(SDL_SOUND_VERSION_STRING "${SDL_sound_VERSION}")
   unset(SDL_SOUND_VERSION_MAJOR_LINE)
   unset(SDL_SOUND_VERSION_MINOR_LINE)
   unset(SDL_SOUND_VERSION_PATCH_LINE)
@@ -454,6 +472,6 @@
 
 find_package_handle_standard_args(SDL_sound
                                   REQUIRED_VARS SDL_SOUND_LIBRARY SDL_SOUND_INCLUDE_DIR
-                                  VERSION_VAR SDL_SOUND_VERSION_STRING)
+                                  VERSION_VAR SDL_sound_VERSION)
 
 cmake_policy(POP)
diff --git a/Modules/FindSDL_ttf.cmake b/Modules/FindSDL_ttf.cmake
index 2569588..25332dd 100644
--- a/Modules/FindSDL_ttf.cmake
+++ b/Modules/FindSDL_ttf.cmake
@@ -6,7 +6,11 @@
 -----------
 
 Finds the SDL_ttf library that provides support for rendering text with TrueType
-fonts in SDL (Simple DirectMedia Layer) applications.
+fonts in SDL (Simple DirectMedia Layer) applications:
+
+.. code-block:: cmake
+
+  find_package(SDL_ttf [<version>] [...])
 
 .. note::
 
@@ -27,7 +31,9 @@
   found.  For backward compatibility, the ``SDL_TTF_FOUND`` variable is also set
   to the same value.
 
-``SDL_TTF_VERSION_STRING``
+``SDL_ttf_VERSION``
+  .. versionadded:: 4.2
+
   The human-readable string containing the version of SDL_ttf found.
 
 ``SDL_TTF_INCLUDE_DIRS``
@@ -36,10 +42,27 @@
 ``SDL_TTF_LIBRARIES``
   Libraries needed to link against to use SDL_ttf.
 
+Hints
+^^^^^
+
+This module accepts the following variables:
+
+``SDLDIR``
+  Environment variable that can be set to help locate an SDL library installed
+  in a custom location.  It should point to the installation destination that
+  was used when configuring, building, and installing SDL library:
+  ``./configure --prefix=$SDLDIR``.
+
 Deprecated Variables
 ^^^^^^^^^^^^^^^^^^^^
 
-For backward compatibility the following variables are also set:
+The following variables are provided for backward compatibility:
+
+``SDL_TTF_VERSION_STRING``
+  .. deprecated:: 4.2
+    Use the ``SDL_ttf_VERSION``.
+
+  The human-readable string containing the version of SDL_ttf found.
 
 ``SDLTTF_FOUND``
   .. deprecated:: 2.8.10
@@ -53,17 +76,6 @@
   .. deprecated:: 2.8.10
     Replaced with ``SDL_TTF_LIBRARIES``, which has the same value.
 
-Hints
-^^^^^
-
-This module accepts the following variables:
-
-``SDLDIR``
-  Environment variable that can be set to help locate an SDL library installed
-  in a custom location.  It should point to the installation destination that
-  was used when configuring, building, and installing SDL library:
-  ``./configure --prefix=$SDLDIR``.
-
 Examples
 ^^^^^^^^
 
@@ -149,7 +161,8 @@
   string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_TTF_VERSION_MAJOR "${SDL_TTF_VERSION_MAJOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_TTF_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL_TTF_VERSION_MINOR "${SDL_TTF_VERSION_MINOR_LINE}")
   string(REGEX REPLACE "^#define[ \t]+SDL_TTF_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL_TTF_VERSION_PATCH "${SDL_TTF_VERSION_PATCH_LINE}")
-  set(SDL_TTF_VERSION_STRING ${SDL_TTF_VERSION_MAJOR}.${SDL_TTF_VERSION_MINOR}.${SDL_TTF_VERSION_PATCH})
+  set(SDL_ttf_VERSION ${SDL_TTF_VERSION_MAJOR}.${SDL_TTF_VERSION_MINOR}.${SDL_TTF_VERSION_PATCH})
+  set(SDL_TTF_VERSION_STRING "${SDL_ttf_VERSION}")
   unset(SDL_TTF_VERSION_MAJOR_LINE)
   unset(SDL_TTF_VERSION_MINOR_LINE)
   unset(SDL_TTF_VERSION_PATCH_LINE)
@@ -165,7 +178,7 @@
 
 find_package_handle_standard_args(SDL_ttf
                                   REQUIRED_VARS SDL_TTF_LIBRARIES SDL_TTF_INCLUDE_DIRS
-                                  VERSION_VAR SDL_TTF_VERSION_STRING)
+                                  VERSION_VAR SDL_ttf_VERSION)
 
 # for backward compatibility
 set(SDLTTF_LIBRARY ${SDL_TTF_LIBRARIES})
diff --git a/Modules/FindSQLite3.cmake b/Modules/FindSQLite3.cmake
index 914b84a..b7fe4b1 100644
--- a/Modules/FindSQLite3.cmake
+++ b/Modules/FindSQLite3.cmake
@@ -7,9 +7,14 @@
 
 .. versionadded:: 3.14
 
-Finds the SQLite 3 library.  SQLite is a small, fast, self-contained,
-high-reliability, and full-featured SQL database engine written in C, intended
-for embedding in applications.
+Finds the SQLite 3 library:
+
+.. code-block:: cmake
+
+  find_package(SQLite3 [<version>] [...])
+
+SQLite is a small, fast, self-contained, high-reliability, and full-featured
+SQL database engine written in C, intended for embedding in applications.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -23,17 +28,21 @@
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module sets the following variables:
+This module defines the following variables:
+
+``SQLite3_FOUND``
+  Boolean indicating whether (the requested version of) SQLite library is
+  found.
+
+``SQLite3_VERSION``
+  The version of SQLite library found.
 
 ``SQLite3_INCLUDE_DIRS``
-  Include directories containing the ``sqlite3.h`` and related headers needed
-  to use SQLite.
+  Include directories containing the ``<sqlite3.h>`` and related headers
+  needed to use SQLite.
+
 ``SQLite3_LIBRARIES``
   Libraries needed to link against to use SQLite.
-``SQLite3_VERSION``
-  Version of the SQLite library found.
-``SQLite3_FOUND``
-  Boolean indicating whether the SQLite library is found.
 
 Examples
 ^^^^^^^^
diff --git a/Modules/FindSWIG.cmake b/Modules/FindSWIG.cmake
index 57303e5..23154eb 100644
--- a/Modules/FindSWIG.cmake
+++ b/Modules/FindSWIG.cmake
@@ -5,41 +5,69 @@
 FindSWIG
 --------
 
-Find the Simplified Wrapper and Interface Generator (SWIG_) executable.
+Finds the installed Simplified Wrapper and Interface Generator (SWIG_)
+executable and determines its version:
 
-This module finds an installed SWIG and determines its version.
+.. code-block:: cmake
 
-.. versionadded:: 3.18
-  If a ``COMPONENTS`` or ``OPTIONAL_COMPONENTS`` argument is given to the
-  :command:`find_package` command, it will also determine supported target
-  languages.
+  find_package(SWIG [<version>] [COMPONENTS <langs>...] [...])
 
 .. versionadded:: 3.19
-  When a version is requested, it can be specified as a simple value or as a
-  range. For a detailed description of version range usage and capabilities,
-  refer to the :command:`find_package` command.
+  Support for specifying version range when calling the :command:`find_package`
+  command.  When a version is requested, it can be specified as a single
+  value as before, and now also a version range can be used.  For a detailed
+  description of version range usage and capabilities, refer to the
+  :command:`find_package` command.
 
-The module defines the following variables:
+Components
+^^^^^^^^^^
+
+.. versionadded:: 3.18
+
+This module supports optional components to specify target languages.
+
+If a ``COMPONENTS`` or ``OPTIONAL_COMPONENTS`` argument is given to the
+:command:`find_package` command, it will also determine supported target
+languages.
+
+.. code-block:: cmake
+
+  find_package(SWIG [COMPONENTS <langs>...] [OPTIONAL_COMPONENTS <langs>...])
+
+Any ``COMPONENTS`` given to ``find_package()`` should be the names of
+supported target languages as provided to the ``LANGUAGE`` argument of
+:command:`swig_add_library`, such as ``python`` or ``perl5``.  Language
+names *must* be lowercase.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
 
 ``SWIG_FOUND``
-  Whether SWIG and any required components were found on the system.
-``SWIG_EXECUTABLE``
-  Path to the SWIG executable.
-``SWIG_DIR``
-  Path to the installed SWIG ``Lib`` directory (result of ``swig -swiglib``).
+  Boolean indicating whether (the requested version of) SWIG and any required
+  components are found on the system.
 ``SWIG_VERSION``
   SWIG executable version (result of ``swig -version``).
 ``SWIG_<lang>_FOUND``
   If ``COMPONENTS`` or ``OPTIONAL_COMPONENTS`` are requested, each available
   target language ``<lang>`` (lowercase) will be set to TRUE.
+``SWIG_DIR``
+  Path to the installed SWIG ``Lib`` directory (result of ``swig -swiglib``).
 
-Any ``COMPONENTS`` given to ``find_package`` should be the names of supported
-target languages as provided to the LANGUAGE argument of ``swig_add_library``,
-such as ``python`` or ``perl5``. Language names *must* be lowercase.
+Cache Variables
+^^^^^^^^^^^^^^^
 
-All information is collected from the ``SWIG_EXECUTABLE``, so the version
-to be found can be changed from the command line by means of setting
-``SWIG_EXECUTABLE``.
+The following cache variables may also be set:
+
+``SWIG_EXECUTABLE``
+  The path to the SWIG executable.
+
+  This executable is used to retrieve all information for this module. It can
+  be also manually set to change the version to be found from the command line.
+
+Examples
+^^^^^^^^
 
 Example usage requiring SWIG 4.0 or higher and Python language support, with
 optional Fortran support:
@@ -54,8 +82,23 @@
      endif()
    endif()
 
-.. _SWIG: https://swig.org
+This module is commonly used in conjunction with the :module:`UseSWIG` module:
 
+.. code-block:: cmake
+
+  find_package(SWIG COMPONENTS python)
+  if(SWIG_FOUND)
+    include(UseSWIG)
+
+    swig_add_library(mymod LANGUAGE python SOURCES mymod.i)
+  endif()
+
+See Also
+^^^^^^^^
+
+* The :module:`UseSWIG` module to use SWIG in CMake.
+
+.. _SWIG: https://swig.org
 #]=======================================================================]
 
 include(FindPackageHandleStandardArgs)
diff --git a/Modules/FindSelfPackers.cmake b/Modules/FindSelfPackers.cmake
index dd50ba4..3742165 100644
--- a/Modules/FindSelfPackers.cmake
+++ b/Modules/FindSelfPackers.cmake
@@ -5,7 +5,11 @@
 FindSelfPackers
 ---------------
 
-Finds `UPX <https://upx.github.io/>`_, the Ultimate Packer for eXecutables.
+Finds `UPX <https://upx.github.io/>`_, the Ultimate Packer for eXecutables:
+
+.. code-block:: cmake
+
+  find_package(SelfPackers [...])
 
 This module searches for executable packers-tools that compress executables or
 shared libraries into on-the-fly, self-extracting versions.  It currently
@@ -14,7 +18,7 @@
 Cache Variables
 ^^^^^^^^^^^^^^^
 
-The following cache variables may be set:
+The following cache variables may also be set:
 
 ``SELF_PACKER_FOR_EXECUTABLE``
   Path to the executable packer for compressing executables.
diff --git a/Modules/FindSquish.cmake b/Modules/FindSquish.cmake
index ea96e7b..4b72a8d 100644
--- a/Modules/FindSquish.cmake
+++ b/Modules/FindSquish.cmake
@@ -5,9 +5,15 @@
 FindSquish
 ----------
 
-Finds Squish, a cross-platform automated GUI testing framework for applications
-built on various GUI technologies.  Squish supports testing of both native and
-cross-platform toolkits, such as Qt, Java, and Tk.
+Finds Squish, a cross-platform automated GUI testing framework for
+applications built on various GUI technologies:
+
+.. code-block:: cmake
+
+  find_package(Squish [<version>] [...])
+
+Squish supports testing of both native and cross-platform toolkits, such as
+Qt, Java, and Tk.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
@@ -15,22 +21,15 @@
 This module defines the following variables:
 
 ``Squish_FOUND``
-  Boolean indicating whether the (requested version of) Squish is found.  For
-  backward compatibility, the ``SQUISH_FOUND`` variable is also set to the same
-  value.
+  Boolean indicating whether (the requested version of) Squish is found.
+  For backward compatibility, the ``SQUISH_FOUND`` variable is also set to
+  the same value.
 
-``SQUISH_VERSION``
+``Squish_VERSION``
+  .. versionadded:: 4.2
+
   The full version of the Squish found.
 
-``SQUISH_VERSION_MAJOR``
-  The major version of the Squish found.
-
-``SQUISH_VERSION_MINOR``
-  The minor version of the Squish found.
-
-``SQUISH_VERSION_PATCH``
-  The patch version of the Squish found.
-
 ``SQUISH_INSTALL_DIR_FOUND``
   Boolean indicating whether the Squish installation directory is found.
 
@@ -162,6 +161,35 @@
     A string of one or more (semicolon-separated list) test wrappers needed by
     the test case.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``SQUISH_VERSION``
+  .. deprecated:: 4.2
+    Superseded by the ``Squish_VERSION``.
+
+  The full version of the Squish found.
+
+``SQUISH_VERSION_MAJOR``
+  .. deprecated:: 4.2
+    Superseded by the ``Squish_VERSION``.
+
+  The major version of the Squish found.
+
+``SQUISH_VERSION_MINOR``
+  .. deprecated:: 4.2
+    Superseded by the ``Squish_VERSION``.
+
+  The minor version of the Squish found.
+
+``SQUISH_VERSION_PATCH``
+  .. deprecated:: 4.2
+    Superseded by the ``Squish_VERSION``.
+
+  The patch version of the Squish found.
+
 Examples
 ^^^^^^^^
 
@@ -254,10 +282,11 @@
 endif()
 
 
-set(SQUISH_VERSION)
-set(SQUISH_VERSION_MAJOR)
-set(SQUISH_VERSION_MINOR)
-set(SQUISH_VERSION_PATCH)
+unset(Squish_VERSION)
+unset(SQUISH_VERSION)
+unset(SQUISH_VERSION_MAJOR)
+unset(SQUISH_VERSION_MINOR)
+unset(SQUISH_VERSION_PATCH)
 
 # record if executables are set
 if(SQUISH_CLIENT_EXECUTABLE)
@@ -269,7 +298,8 @@
     set(SQUISH_VERSION_MAJOR "${CMAKE_MATCH_1}")
     set(SQUISH_VERSION_MINOR "${CMAKE_MATCH_2}")
     set(SQUISH_VERSION_PATCH "${CMAKE_MATCH_3}")
-    set(SQUISH_VERSION "${SQUISH_VERSION_MAJOR}.${SQUISH_VERSION_MINOR}.${SQUISH_VERSION_PATCH}" )
+    set(Squish_VERSION "${SQUISH_VERSION_MAJOR}.${SQUISH_VERSION_MINOR}.${SQUISH_VERSION_PATCH}" )
+    set(SQUISH_VERSION "${Squish_VERSION}")
   endif()
 else()
   set(SQUISH_CLIENT_EXECUTABLE_FOUND 0)
@@ -284,7 +314,7 @@
 # record if Squish was found
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Squish  REQUIRED_VARS  SQUISH_INSTALL_DIR SQUISH_CLIENT_EXECUTABLE SQUISH_SERVER_EXECUTABLE
-                                          VERSION_VAR  SQUISH_VERSION )
+                                          VERSION_VAR Squish_VERSION)
 
 
 set(_SQUISH_MODULE_DIR "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/Modules/FindTCL.cmake b/Modules/FindTCL.cmake
index 5ed3791..d0208d3 100644
--- a/Modules/FindTCL.cmake
+++ b/Modules/FindTCL.cmake
@@ -5,7 +5,11 @@
 FindTCL
 -------
 
-Finds the Tcl (Tool Command Language), dynamic programming language.
+Finds the Tcl (Tool Command Language), dynamic programming language:
+
+.. code-block:: cmake
+
+  find_package(TCL [...])
 
 This module locates a Tcl installation, including its include directories and
 libraries, and determines the appropriate Tcl library name for linking.  As part
@@ -44,14 +48,12 @@
 ``TK_WISH``
   The path to the ``wish`` windowing shell command-line executable.
 
-
 Other Libraries
 ^^^^^^^^^^^^^^^
 
 The Tcl Stub Library can be found using the separate :module:`FindTclStub`
 module.
 
-
 Examples
 ^^^^^^^^
 
diff --git a/Modules/FindTIFF.cmake b/Modules/FindTIFF.cmake
index c756b93..c1fa789 100644
--- a/Modules/FindTIFF.cmake
+++ b/Modules/FindTIFF.cmake
@@ -5,14 +5,25 @@
 FindTIFF
 --------
 
-Finds the `TIFF library <https://libtiff.gitlab.io/libtiff/>`_ (``libtiff``).
+Finds the `TIFF library <https://libtiff.gitlab.io/libtiff/>`_ (``libtiff``):
+
+.. code-block:: cmake
+
+  find_package(TIFF [<version>] [COMPONENTS <components>...] [...])
+
 This module also takes into account the upstream TIFF library's exported CMake
 package configuration, if available.
 
 Components
 ^^^^^^^^^^
 
-This module supports the following components:
+This module supports optional components which can be specified with:
+
+.. code-block:: cmake
+
+  find_package(TIFF [COMPONENTS <components>...])
+
+Supported components include:
 
 ``CXX``
   .. versionadded:: 3.19
@@ -20,12 +31,6 @@
   Optional component that ensures that the C++ wrapper library (``libtiffxx``)
   is found.
 
-Components can be specified using the standard syntax:
-
-.. code-block:: cmake
-
-  find_package(TIFF [COMPONENTS <components>...])
-
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
@@ -51,10 +56,12 @@
 This module defines the following variables:
 
 ``TIFF_FOUND``
-  Boolean indicating whether the TIFF is found.
+  Boolean indicating whether (the requested version of) TIFF is found.
 
-``TIFF_VERSION_STRING``
-  The version of the TIFF library found.
+``TIFF_VERSION``
+  .. versionadded:: 4.2
+
+  The version of TIFF library found.
 
 ``TIFF_INCLUDE_DIRS``
   The directory containing the TIFF headers.
@@ -90,6 +97,17 @@
 
   The path to the TIFFXX library for debug configurations.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``TIFF_VERSION_STRING``
+  .. deprecated:: 4.2
+    Superseded by the ``TIFF_VERSION``.
+
+  The version of TIFF library found.
+
 Examples
 ^^^^^^^^
 
@@ -244,7 +262,8 @@
       endif ()
     endif ()
   endif ()
-  set(TIFF_VERSION_STRING "${Tiff_VERSION}")
+  set(TIFF_VERSION "${Tiff_VERSION}")
+  set(TIFF_VERSION_STRING "${TIFF_VERSION}")
   foreach (_TIFF_component IN LISTS TIFF_FIND_COMPONENTS)
     set(TIFF_${_TIFF_component}_FOUND "${Tiff_${_TIFF_component}_FOUND}")
   endforeach ()
@@ -254,7 +273,7 @@
   find_package_handle_standard_args(TIFF
                                     HANDLE_COMPONENTS
                                     REQUIRED_VARS Tiff_DIR
-                                    VERSION_VAR TIFF_VERSION_STRING)
+                                    VERSION_VAR TIFF_VERSION)
 
   cmake_policy(POP)
   return ()
@@ -280,7 +299,8 @@
          REGEX "^#define[\t ]+TIFFLIB_VERSION_STR[\t ]+\"LIBTIFF, Version .*")
 
     string(REGEX REPLACE "^#define[\t ]+TIFFLIB_VERSION_STR[\t ]+\"LIBTIFF, Version +([^ \\n]*).*"
-           "\\1" TIFF_VERSION_STRING "${tiff_version_str}")
+           "\\1" TIFF_VERSION "${tiff_version_str}")
+    set(TIFF_VERSION_STRING "${TIFF_VERSION}")
     unset(tiff_version_str)
 endif()
 
@@ -316,7 +336,7 @@
 find_package_handle_standard_args(TIFF
                                   HANDLE_COMPONENTS
                                   REQUIRED_VARS TIFF_LIBRARY TIFF_INCLUDE_DIR
-                                  VERSION_VAR TIFF_VERSION_STRING)
+                                  VERSION_VAR TIFF_VERSION)
 
 if(TIFF_FOUND)
   set(TIFF_LIBRARIES ${TIFF_LIBRARY})
diff --git a/Modules/FindTclStub.cmake b/Modules/FindTclStub.cmake
index ac0b2a6..7c8d52c 100644
--- a/Modules/FindTclStub.cmake
+++ b/Modules/FindTclStub.cmake
@@ -6,7 +6,11 @@
 -----------
 
 Finds the Tcl Stub Library, which is used for building version-independent Tcl
-extensions.
+extensions:
+
+.. code-block:: cmake
+
+  find_package(TclStub [...])
 
 Tcl (Tool Command Language) is a dynamic programming language, and the Tcl Stub
 Library provides a mechanism to allow Tcl extensions to be compiled in a way
diff --git a/Modules/FindTclsh.cmake b/Modules/FindTclsh.cmake
index 81c666a..9765476 100644
--- a/Modules/FindTclsh.cmake
+++ b/Modules/FindTclsh.cmake
@@ -6,7 +6,11 @@
 ---------
 
 Finds the Tcl shell command-line executable (``tclsh``), which includes the Tcl
-(Tool Command Language) interpreter.
+(Tool Command Language) interpreter:
+
+.. code-block:: cmake
+
+  find_package(Tclsh [...])
 
 Result Variables
 ^^^^^^^^^^^^^^^^
diff --git a/Modules/FindThreads.cmake b/Modules/FindThreads.cmake
index 26bd7d3..f3cf823 100644
--- a/Modules/FindThreads.cmake
+++ b/Modules/FindThreads.cmake
@@ -5,27 +5,77 @@
 FindThreads
 -----------
 
-This module determines the thread library of the system.
+Finds and determines the thread library of the system for multithreading
+support:
+
+.. code-block:: cmake
+
+  find_package(Threads [...])
+
+Multithreading enables concurrent execution within a single program,
+typically by creating multiple threads of execution.  Most commonly, this
+is done using libraries such as POSIX Threads (``pthreads``) on Unix-like
+systems or Windows threads on Windows.
+
+This module abstracts the platform-specific differences and detects how to
+enable thread support - whether it requires linking to a specific library,
+adding compiler flags (like ``-pthread``), or both.  On some platforms,
+threading is also implicitly available in default libraries without the
+need to use additional flags or libraries.
+
+This module is suitable for use in both C and C++ projects (and occasionally
+other compiled languages) that rely on system-level threading APIs.
+
+Using this module ensures that project builds correctly across different
+platforms by handling the detection and setup of thread support in a
+portable way.
+
+C and C++ Language Standards
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The C11 standard introduced a minimal cross-platform thread API via
+``<threads.h>`` header file, and C++11 added ``<thread>`` header to the
+standard library, offering high-level multithreading support.  These standard
+headers allow writing portable threaded code at the language level, without
+directly using platform-specific APIs like ``pthreads`` or Windows threads.
+
+However, even with standard C11 or C++11 threads support available, there
+may still be a need for platform-specific compiler or linker flags (e.g.,
+``-pthread`` on Unix-like systems) for some applications.  This is where
+FindThreads remains relevant - it ensures these flags and any required
+libraries are correctly set up, even if not explicitly using system APIs.
+
+In short:
+
+* Use ``<thread>`` (C++11 and later) or ``<threads.h>`` (C11) in source code
+  for portability and simpler syntax.
+
+* Use ``find_package(Threads)`` in CMake project when application needs the
+  traditional threading support and to ensure code compiles and links
+  correctly across different platforms.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-.. versionadded:: 3.1
-
-This module defines the following :prop_tgt:`IMPORTED` target:
+This module provides the following :ref:`Imported Targets`:
 
 ``Threads::Threads``
-  The thread library, if found.
+  .. versionadded:: 3.1
+
+  Target encapsulating the usage requirements to enable threading through
+  flags or a threading library, if found.  This target is available if
+  threads are detected as supported.
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-The following variables are set:
+This module defines the following variables:
 
 ``Threads_FOUND``
-  If a supported thread library was found.
+  Boolean indicating whether Threads is supported, either through a separate
+  library or a standard library.
 ``CMAKE_THREAD_LIBS_INIT``
-  The thread library to use. This may be empty if the thread functions
+  The thread library to use.  This may be empty if the thread functions
   are provided by the system libraries and no special flags are needed
   to use them.
 ``CMAKE_USE_WIN32_THREADS_INIT``
@@ -38,17 +88,30 @@
 Variables Affecting Behavior
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-.. variable:: THREADS_PREFER_PTHREAD_FLAG
+This module accepts the following variables before calling
+``find_package(Threads)``:
 
+``THREADS_PREFER_PTHREAD_FLAG``
   .. versionadded:: 3.1
 
-  If the use of the -pthread compiler and linker flag is preferred then
-  the caller can set this variable to TRUE. The compiler flag can only be
-  used with the imported target. Use of both the imported target as well
-  as this switch is highly recommended for new code.
+  If the use of the ``-pthread`` compiler and linker flag is preferred then
+  the caller can set this variable to boolean true.  The compiler flag can
+  only be used with the imported target.  Use of both the imported target
+  as well as this switch is highly recommended for new code.
 
   This variable has no effect if the system libraries provide the
   thread functions, i.e. when ``CMAKE_THREAD_LIBS_INIT`` will be empty.
+
+Examples
+^^^^^^^^
+
+Finding Threads and linking the imported target to a project target:
+
+.. code-block:: cmake
+
+  set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+  find_package(Threads)
+  target_link_libraries(example PRIVATE Threads::Threads)
 #]=======================================================================]
 
 include (CheckLibraryExists)
@@ -225,7 +288,7 @@
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Threads DEFAULT_MSG Threads_FOUND)
 
-if(THREADS_FOUND AND NOT TARGET Threads::Threads)
+if(Threads_FOUND AND NOT TARGET Threads::Threads)
   add_library(Threads::Threads INTERFACE IMPORTED)
 
   if(THREADS_HAVE_PTHREAD_ARG)
diff --git a/Modules/FindVulkan.cmake b/Modules/FindVulkan.cmake
index e10051d..5c85458 100644
--- a/Modules/FindVulkan.cmake
+++ b/Modules/FindVulkan.cmake
@@ -8,8 +8,13 @@
 .. versionadded:: 3.7
 
 Finds Vulkan, a low-overhead, cross-platform 3D graphics and computing API,
-along with related development tools typically provided by the Vulkan SDK.  This
-includes commonly used utilities such as shader compilers and SPIR-V tools
+along with related development tools typically provided by the Vulkan SDK:
+
+.. code-block:: cmake
+
+  find_package(Vulkan [<version>] [COMPONENTS <components>...] [...])
+
+Vulkan includes commonly used utilities such as shader compilers and SPIR-V tools
 (e.g., DXC, ``glslc``, ``glslang``, etc.) that support Vulkan-based development
 workflows.
 
diff --git a/Modules/FindWget.cmake b/Modules/FindWget.cmake
index ef63d1e..dafbc37 100644
--- a/Modules/FindWget.cmake
+++ b/Modules/FindWget.cmake
@@ -6,15 +6,19 @@
 --------
 
 This module finds the ``wget`` command-line tool for retrieving content from web
-servers.
+servers:
+
+.. code-block:: cmake
+
+  find_package(Wget [...])
 
 Result Variables
 ^^^^^^^^^^^^^^^^
 
-This module defines the following local variables:
+This module defines the following variables:
 
 ``Wget_FOUND``
-  True if ``wget`` has been found.
+  Boolean indicating whether ``wget`` has been found.
 
 Cache Variables
 ^^^^^^^^^^^^^^^
diff --git a/Modules/FindWish.cmake b/Modules/FindWish.cmake
index 00b1201..e0a0c1b 100644
--- a/Modules/FindWish.cmake
+++ b/Modules/FindWish.cmake
@@ -5,7 +5,11 @@
 FindWish
 --------
 
-Finds ``wish``, a simple windowing shell command-line executable.
+Finds ``wish``, a simple windowing shell command-line executable:
+
+.. code-block:: cmake
+
+  find_package(Wish [...])
 
 This module is commonly used in conjunction with finding a TCL installation (see
 the :module:`FindTCL` module).  It helps determine where the TCL include paths
@@ -17,7 +21,7 @@
 Cache Variables
 ^^^^^^^^^^^^^^^
 
-The following cache variables may be set:
+The following cache variables may also be set:
 
 ``TK_WISH``
   The path to the ``wish`` executable.
diff --git a/Modules/FindXCTest.cmake b/Modules/FindXCTest.cmake
index 696718b..e345fa4 100644
--- a/Modules/FindXCTest.cmake
+++ b/Modules/FindXCTest.cmake
@@ -7,7 +7,11 @@
 
 .. versionadded:: 3.3
 
-Finds the XCTest framework for writing unit tests in Xcode projects.
+Finds the XCTest framework for writing unit tests in Xcode projects:
+
+.. code-block:: cmake
+
+  find_package(XCTest [...])
 
 .. note::
 
diff --git a/Modules/FindXMLRPC.cmake b/Modules/FindXMLRPC.cmake
index 949f755..dc833f9 100644
--- a/Modules/FindXMLRPC.cmake
+++ b/Modules/FindXMLRPC.cmake
@@ -5,9 +5,15 @@
 FindXMLRPC
 ----------
 
-Finds the native XML-RPC library for C and C++.  XML-RPC is a standard network
-protocol that enables remote procedure calls (RPC) between systems.  It encodes
-requests and responses in XML and uses HTTP as the transport mechanism.
+Finds the native XML-RPC library for C and C++:
+
+.. code-block:: cmake
+
+  find_package(XMLRPC [...] [COMPONENTS <components>...] [...])
+
+XML-RPC is a standard network protocol that enables remote procedure calls
+(RPC) between systems.  It encodes requests and responses in XML and uses
+HTTP as the transport mechanism.
 
 Components
 ^^^^^^^^^^
@@ -21,7 +27,7 @@
 utility can be used.
 
 In CMake, these features can be specified as components with the
-``find_package()`` command:
+:command:`find_package` command:
 
 .. code-block:: cmake
 
@@ -50,29 +56,46 @@
 ``openssl``
   OpenSSL convenience functions.
 
+If no components are specified, this module searches for XML-RPC library and
+its include directories without additional features.
+
 Result Variables
 ^^^^^^^^^^^^^^^^
 
 This module defines the following variables:
 
+``XMLRPC_FOUND``
+  Boolean indicating whether the XML-RPC library and all its requested
+  components are found.
 ``XMLRPC_INCLUDE_DIRS``
   Include directories containing ``xmlrpc.h`` and other headers needed to use
   the XML-RPC library.
 ``XMLRPC_LIBRARIES``
   List of libraries needed for linking to XML-RPC library and its requested
   features.
-``XMLRPC_FOUND``
-  Boolean indicating whether the XML-RPC library and all its requested
-  components are found.
 
 Examples
 ^^^^^^^^
 
-Finding XML-RPC library and its ``client`` feature to use in the project:
+Finding XML-RPC library and its ``client`` feature, and conditionally
+creating an interface :ref:`imported target <Imported Targets>` that
+encapsulates its usage requirements for linking to a project target:
 
 .. code-block:: cmake
 
   find_package(XMLRPC REQUIRED COMPONENTS client)
+
+  if(XMLRPC_FOUND AND NOT TARGET XMLRPC::XMLRPC)
+    add_library(XMLRPC::XMLRPC INTERFACE IMPORTED)
+    set_target_properties(
+      XMLRPC::XMLRPC
+      PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${XMLRPC_INCLUDE_DIRS}"
+        INTERFACE_LINK_LIBRARIES "${XMLRPC_LIBRARIES}"
+    )
+  endif()
+
+  target_link_libraries(example PRIVATE XMLRPC::XMLRPC)
 #]=======================================================================]
 
 # First find the config script from which to obtain other values.
diff --git a/Modules/FindXalanC.cmake b/Modules/FindXalanC.cmake
index 26d859b..6959495 100644
--- a/Modules/FindXalanC.cmake
+++ b/Modules/FindXalanC.cmake
@@ -7,7 +7,11 @@
 
 .. versionadded:: 3.5
 
-Finds the Apache Xalan-C++ XSL transform processor headers and libraries.
+Finds the Apache Xalan-C++ XSL transform processor headers and libraries:
+
+.. code-block:: cmake
+
+  find_package(XalaxC [<version>] [...])
 
 .. note::
 
@@ -29,7 +33,7 @@
 This module defines the following variables:
 
 ``XalanC_FOUND``
-  Boolean indicating whether the Xalan-C++ is found.
+  Boolean indicating whether (the requested version of) Xalan-C++ is found.
 ``XalanC_VERSION``
   The version of the found Xalan-C++ library.
 ``XalanC_INCLUDE_DIRS``
diff --git a/Modules/FindXercesC.cmake b/Modules/FindXercesC.cmake
index c172d28..d33868b 100644
--- a/Modules/FindXercesC.cmake
+++ b/Modules/FindXercesC.cmake
@@ -7,12 +7,16 @@
 
 .. versionadded:: 3.1
 
-Finds the Apache Xerces-C++ validating XML parser headers and libraries.
+Finds the Apache Xerces-C++ validating XML parser headers and libraries:
+
+.. code-block:: cmake
+
+  find_package(XercesC [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets`:
+This module provides the following :ref:`Imported Targets`:
 
 ``XercesC::XercesC``
   .. versionadded:: 3.5
@@ -26,7 +30,7 @@
 This module defines the following variables:
 
 ``XercesC_FOUND``
-  Boolean indicating whether the Xerces-C++ is found.
+  Boolean indicating whether (the requested version of) Xerces-C++ is found.
 ``XercesC_VERSION``
   The version of the found Xerces-C++ library.
 ``XercesC_INCLUDE_DIRS``
diff --git a/Modules/FindZLIB.cmake b/Modules/FindZLIB.cmake
index fd7d41d..cfb1acd 100644
--- a/Modules/FindZLIB.cmake
+++ b/Modules/FindZLIB.cmake
@@ -5,7 +5,11 @@
 FindZLIB
 --------
 
-Finds the native zlib data compression library.
+Finds the native zlib data compression library:
+
+.. code-block:: cmake
+
+  find_package(ZLIB [<version>] [...])
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
@@ -23,6 +27,14 @@
 
 This module defines the following variables:
 
+``ZLIB_FOUND``
+  Boolean indicating whether (the requested version of) zlib is found.
+
+``ZLIB_VERSION``
+  .. versionadded:: 3.26
+
+  The version of zlib found.
+
 ``ZLIB_INCLUDE_DIRS``
   Include directories containing ``zlib.h`` and other headers needed to use
   zlib.
@@ -33,58 +45,6 @@
   .. versionchanged:: 3.4
     Debug and Release library variants can be now found separately.
 
-``ZLIB_FOUND``
-  True if zlib is found.
-
-``ZLIB_VERSION``
-  .. versionadded:: 3.26
-
-  The version of zlib found.
-
-Legacy Variables
-^^^^^^^^^^^^^^^^
-
-The following variables are provided for backward compatibility:
-
-``ZLIB_VERSION_MAJOR``
-  The major version of zlib.
-
-  .. versionchanged:: 3.26
-    Superseded by ``ZLIB_VERSION``.
-
-``ZLIB_VERSION_MINOR``
-  The minor version of zlib.
-
-  .. versionchanged:: 3.26
-    Superseded by ``ZLIB_VERSION``.
-
-``ZLIB_VERSION_PATCH``
-  The patch version of zlib.
-
-  .. versionchanged:: 3.26
-    Superseded by ``ZLIB_VERSION``.
-
-``ZLIB_VERSION_TWEAK``
-  The tweak version of zlib.
-
-  .. versionchanged:: 3.26
-    Superseded by ``ZLIB_VERSION``.
-
-``ZLIB_VERSION_STRING``
-  The version of zlib found (x.y.z).
-
-  .. versionchanged:: 3.26
-    Superseded by ``ZLIB_VERSION``.
-
-``ZLIB_MAJOR_VERSION``
-  The major version of zlib.  Superseded by ``ZLIB_VERSION_MAJOR``.
-
-``ZLIB_MINOR_VERSION``
-  The minor version of zlib.  Superseded by ``ZLIB_VERSION_MINOR``.
-
-``ZLIB_PATCH_VERSION``
-  The patch version of zlib.  Superseded by ``ZLIB_VERSION_PATCH``.
-
 Hints
 ^^^^^
 
@@ -100,6 +60,59 @@
   Set this variable to ``ON`` before calling ``find_package(ZLIB)`` to look for
   static libraries.  Default is ``OFF``.
 
+Deprecated Variables
+^^^^^^^^^^^^^^^^^^^^
+
+The following variables are provided for backward compatibility:
+
+``ZLIB_VERSION_MAJOR``
+  .. deprecated:: 3.26
+    Superseded by ``ZLIB_VERSION``.
+
+  The major version of zlib.
+
+``ZLIB_VERSION_MINOR``
+  .. deprecated:: 3.26
+    Superseded by ``ZLIB_VERSION``.
+
+  The minor version of zlib.
+
+``ZLIB_VERSION_PATCH``
+  .. deprecated:: 3.26
+    Superseded by ``ZLIB_VERSION``.
+
+  The patch version of zlib.
+
+``ZLIB_VERSION_TWEAK``
+  .. deprecated:: 3.26
+    Superseded by ``ZLIB_VERSION``.
+
+  The tweak version of zlib.
+
+``ZLIB_VERSION_STRING``
+  .. deprecated:: 3.26
+    Superseded by ``ZLIB_VERSION``.
+
+  The version of zlib found (x.y.z).
+
+``ZLIB_MAJOR_VERSION``
+  .. deprecated:: 3.26
+    Superseded by ``ZLIB_VERSION``.
+
+  The major version of zlib.
+
+``ZLIB_MINOR_VERSION``
+  .. deprecated:: 3.26
+    Superseded by ``ZLIB_VERSION``.
+
+  The minor version of zlib.
+
+``ZLIB_PATCH_VERSION``
+  .. deprecated:: 3.26
+    Superseded by ``ZLIB_VERSION``.
+
+  The patch version of zlib.
+
 Examples
 ^^^^^^^^
 
diff --git a/Modules/FindwxWindows.cmake b/Modules/FindwxWindows.cmake
index 88af70c..a9126c8 100644
--- a/Modules/FindwxWindows.cmake
+++ b/Modules/FindwxWindows.cmake
@@ -11,7 +11,11 @@
 
 Finds the wxWidgets (formerly known as wxWindows) installation and determines
 the locations of its include directories and libraries, as well as the name of
-the library.
+the library:
+
+.. code-block:: cmake
+
+  find_package(wxWindows [...])
 
 wxWidgets 2.6.x is supported for monolithic builds, such as those compiled in
 the ``wx/build/msw`` directory using:
@@ -57,7 +61,7 @@
 Deprecated Variables
 ^^^^^^^^^^^^^^^^^^^^
 
-These variables are provided for backward compatibility:
+The following variables are provided for backward compatibility:
 
 ``CMAKE_WX_CAN_COMPILE``
   .. deprecated:: 1.8
@@ -78,7 +82,7 @@
 Examples
 ^^^^^^^^
 
-Example: Finding wxWidgets in earlier CMake versions
+Example: Finding wxWidgets in Earlier CMake Versions
 """"""""""""""""""""""""""""""""""""""""""""""""""""
 
 In earlier versions of CMake, wxWidgets (wxWindows) could be found using:
diff --git a/Modules/FortranCInterface.cmake b/Modules/FortranCInterface.cmake
index 70ad3c7..d559ab7 100644
--- a/Modules/FortranCInterface.cmake
+++ b/Modules/FortranCInterface.cmake
@@ -5,25 +5,39 @@
 FortranCInterface
 -----------------
 
-Fortran/C Interface Detection
+This module provides variables and commands to detect Fortran/C Interface.
 
-This module automatically detects the API by which C and Fortran
-languages interact.
+Load this module in a CMake project with:
 
-Module Variables
-^^^^^^^^^^^^^^^^
+.. code-block:: cmake
 
-Variables that indicate if the mangling is found:
+  include(FortranCInterface)
+
+This module automatically detects the API by which C and Fortran languages
+interact.
+
+Variables
+^^^^^^^^^
+
+Result Variables
+""""""""""""""""
+
+Including this module defines the following variables that indicate if the
+mangling is found:
 
 ``FortranCInterface_GLOBAL_FOUND``
-  Global subroutines and functions.
+  Boolean indicating whether global subroutines and functions are available.
 
 ``FortranCInterface_MODULE_FOUND``
-  Module subroutines and functions (declared by "MODULE PROCEDURE").
+  Boolean indicating whether module subroutines and functions (declared by
+  ``MODULE PROCEDURE``) are available.
+
+Input Variables
+"""""""""""""""
 
 This module also provides the following variables to specify
 the detected mangling, though a typical use case does not need
-to reference them and can use the `Module Functions`_ below.
+to reference them and can use the `Commands`_ below.
 
 ``FortranCInterface_GLOBAL_PREFIX``
   Prefix for a global symbol without an underscore.
@@ -99,29 +113,48 @@
     The module name appears *after* the symbol name, i.e.,
     ``<PREFIX><symbol><MIDDLE><module><SUFFIX>``.
 
-Module Functions
-^^^^^^^^^^^^^^^^
+Variables For Additional Manglings
+""""""""""""""""""""""""""""""""""
+
+This module is aware of possible ``GLOBAL`` and ``MODULE`` manglings for
+many Fortran compilers, but it also provides an interface to specify
+new possible manglings.  The following variables can be set before including
+this module to specify additional manglings:
+
+``FortranCInterface_GLOBAL_SYMBOLS``
+
+``FortranCInterface_MODULE_SYMBOLS``
+
+before including this module to specify manglings of the symbols
+``MySub``, ``My_Sub``, ``MyModule:MySub``, and ``My_Module:My_Sub``.
+
+Commands
+^^^^^^^^
+
+This module provides the following commands:
 
 .. command:: FortranCInterface_HEADER
 
-  The ``FortranCInterface_HEADER`` function is provided to generate a
-  C header file containing macros to mangle symbol names:
+  Generates a C header file containing macros to mangle symbol names:
 
   .. code-block:: cmake
 
-    FortranCInterface_HEADER(<file>
-                             [MACRO_NAMESPACE <macro-ns>]
-                             [SYMBOL_NAMESPACE <ns>]
-                             [SYMBOLS [<module>:]<function> ...])
+    FortranCInterface_HEADER(
+      <file>
+      [MACRO_NAMESPACE <macro-ns>]
+      [SYMBOL_NAMESPACE <ns>]
+      [SYMBOLS [<module>:]<function> ...]
+    )
 
-  It generates in ``<file>`` definitions of the following macros:
+  This command generates a ``<file>`` with definitions of the following
+  macros:
 
   .. code-block:: c
 
-     #define FortranCInterface_GLOBAL (name,NAME) ...
-     #define FortranCInterface_GLOBAL_(name,NAME) ...
-     #define FortranCInterface_MODULE (mod,name, MOD,NAME) ...
-     #define FortranCInterface_MODULE_(mod,name, MOD,NAME) ...
+    #define FortranCInterface_GLOBAL (name,NAME) ...
+    #define FortranCInterface_GLOBAL_(name,NAME) ...
+    #define FortranCInterface_MODULE (mod,name, MOD,NAME) ...
+    #define FortranCInterface_MODULE_(mod,name, MOD,NAME) ...
 
   These macros mangle four categories of Fortran symbols, respectively:
 
@@ -139,6 +172,10 @@
     Replace the default ``FortranCInterface_`` prefix with a given
     namespace ``<macro-ns>``.
 
+  ``SYMBOL_NAMESPACE``
+    Prefix all preprocessor definitions generated by the ``SYMBOLS``
+    option with a given namespace ``<ns>``.
+
   ``SYMBOLS``
     List symbols to mangle automatically with C preprocessor definitions::
 
@@ -148,77 +185,71 @@
     If the mangling for some symbol is not known then no preprocessor
     definition is created, and a warning is displayed.
 
-  ``SYMBOL_NAMESPACE``
-    Prefix all preprocessor definitions generated by the ``SYMBOLS``
-    option with a given namespace ``<ns>``.
-
 .. command:: FortranCInterface_VERIFY
 
-  The ``FortranCInterface_VERIFY`` function is provided to verify
-  that the Fortran and C/C++ compilers work together:
+  Verifies that the Fortran and C/C++ compilers work together:
 
   .. code-block:: cmake
 
     FortranCInterface_VERIFY([CXX] [QUIET])
 
-  It tests whether a simple test executable using Fortran and C (and C++
-  when the CXX option is given) compiles and links successfully.  The
-  result is stored in the cache entry ``FortranCInterface_VERIFIED_C``
+  This command tests whether a simple test executable using Fortran and C
+  (and C++ when the ``CXX`` option is given) compiles and links successfully.
+  The result is stored in the cache entry ``FortranCInterface_VERIFIED_C``
   (or ``FortranCInterface_VERIFIED_CXX`` if ``CXX`` is given) as a boolean.
-  If the check fails and ``QUIET`` is not given the function terminates with a
+  If the check fails and ``QUIET`` is not given the command terminates with a
   fatal error message describing the problem.  The purpose of this check
   is to stop a build early for incompatible compiler combinations.  The
   test is built in the ``Release`` configuration.
 
-Example Usage
-^^^^^^^^^^^^^
+Examples
+^^^^^^^^
+
+Examples: Basic Usage
+"""""""""""""""""""""
+
+The following example creates a ``FC.h`` header that defines mangling macros
+``FC_GLOBAL()``, ``FC_GLOBAL_()``, ``FC_MODULE()``, and ``FC_MODULE_()``:
 
 .. code-block:: cmake
 
-   include(FortranCInterface)
-   FortranCInterface_HEADER(FC.h MACRO_NAMESPACE "FC_")
+  include(FortranCInterface)
+  FortranCInterface_HEADER(FC.h MACRO_NAMESPACE "FC_")
 
-This creates a "FC.h" header that defines mangling macros ``FC_GLOBAL()``,
-``FC_GLOBAL_()``, ``FC_MODULE()``, and ``FC_MODULE_()``.
+The next example creates a ``FCMangle.h`` header that defines the same
+``FC_*()`` mangling macros as the previous example plus preprocessor symbols
+``FC_mysub`` and ``FC_mymod_my_sub``:
 
 .. code-block:: cmake
 
-   include(FortranCInterface)
-   FortranCInterface_HEADER(FCMangle.h
-                            MACRO_NAMESPACE "FC_"
-                            SYMBOL_NAMESPACE "FC_"
-                            SYMBOLS mysub mymod:my_sub)
+  include(FortranCInterface)
+  FortranCInterface_HEADER(
+    FCMangle.h
+    MACRO_NAMESPACE "FC_"
+    SYMBOL_NAMESPACE "FC_"
+    SYMBOLS mysub mymod:my_sub
+  )
 
-This creates a "FCMangle.h" header that defines the same ``FC_*()``
-mangling macros as the previous example plus preprocessor symbols
-``FC_mysub`` and ``FC_mymod_my_sub``.
+Example: Additional Manglings
+"""""""""""""""""""""""""""""
 
-Additional Manglings
-^^^^^^^^^^^^^^^^^^^^
-
-FortranCInterface is aware of possible ``GLOBAL`` and ``MODULE`` manglings
-for many Fortran compilers, but it also provides an interface to specify
-new possible manglings.  Set the variables::
-
-   FortranCInterface_GLOBAL_SYMBOLS
-   FortranCInterface_MODULE_SYMBOLS
-
-before including FortranCInterface to specify manglings of the symbols
+The following example shows how to specify manglings of the symbols
 ``MySub``, ``My_Sub``, ``MyModule:MySub``, and ``My_Module:My_Sub``.
-For example, the code:
+The following code tells this module to try given ``GLOBAL`` and ``MODULE``
+manglings.  (The carets point at raw symbol names for clarity in this
+example but are not needed.)
 
 .. code-block:: cmake
 
-   set(FortranCInterface_GLOBAL_SYMBOLS mysub_ my_sub__ MYSUB_)
-     #                                  ^^^^^  ^^^^^^   ^^^^^
-   set(FortranCInterface_MODULE_SYMBOLS
-       __mymodule_MOD_mysub __my_module_MOD_my_sub)
-     #   ^^^^^^^^     ^^^^^   ^^^^^^^^^     ^^^^^^
-   include(FortranCInterface)
+  set(FortranCInterface_GLOBAL_SYMBOLS mysub_ my_sub__ MYSUB_)
+    #                                  ^^^^^  ^^^^^^   ^^^^^
+  set(FortranCInterface_MODULE_SYMBOLS
+      __mymodule_MOD_mysub __my_module_MOD_my_sub)
+    #   ^^^^^^^^     ^^^^^   ^^^^^^^^^     ^^^^^^
 
-tells FortranCInterface to try given ``GLOBAL`` and ``MODULE`` manglings.
-(The carets point at raw symbol names for clarity in this example but
-are not needed.)
+  include(FortranCInterface)
+
+  # ...
 #]=======================================================================]
 
 #-----------------------------------------------------------------------------
diff --git a/Modules/GetPrerequisites.cmake b/Modules/GetPrerequisites.cmake
index f1f5db7..952e66c 100644
--- a/Modules/GetPrerequisites.cmake
+++ b/Modules/GetPrerequisites.cmake
@@ -9,12 +9,19 @@
 
   Use :command:`file(GET_RUNTIME_DEPENDENCIES)` instead.
 
-This module provides functions to analyze and list the dependencies
-(prerequisites) of executable or shared library files.  These functions list the
-shared libraries (``.dll``, ``.dylib``, or ``.so`` files) required by an
+This module provides commands to analyze and list the dependencies
+(prerequisites) of executable or shared library files.  These commands list
+the shared libraries (``.dll``, ``.dylib``, or ``.so`` files) required by an
 executable or shared library.
 
-It determines dependencies using the following platform-specific tools:
+Load this module in CMake with:
+
+.. code-block:: cmake
+
+  include(GetPrerequisites)
+
+This module determines dependencies using the following platform-specific
+tools:
 
 * ``dumpbin`` (Windows)
 * ``objdump`` (MinGW on Windows)
@@ -25,7 +32,10 @@
   The tool specified by the :variable:`CMAKE_OBJDUMP` variable will be used, if
   set.
 
-The following functions are provided by this module:
+Commands
+^^^^^^^^
+
+This module provides the following commands:
 
 * :command:`get_prerequisites`
 * :command:`list_prerequisites`
@@ -40,20 +50,18 @@
   (projects can override it with ``gp_resolved_file_type_override()``)
 * :command:`gp_file_type`
 
-Functions
-^^^^^^^^^
-
 .. command:: get_prerequisites
 
+  Gets the list of shared library files required by specified target:
+
   .. code-block:: cmake
 
     get_prerequisites(<target> <prerequisites-var> <exclude-system> <recurse>
                       <exepath> <dirs> [<rpaths>])
 
-  Gets the list of shared library files required by ``<target>``.  The list
-  in the variable named ``<prerequisites-var>`` should be empty on first
-  entry to this function.  On exit, ``<prerequisites-var>`` will contain the
-  list of required shared library files.
+  The list in the variable named ``<prerequisites-var>`` should be empty on
+  first entry to this command.  On exit, ``<prerequisites-var>`` will contain
+  the list of required shared library files.
 
   The arguments are:
 
@@ -80,16 +88,16 @@
 
   .. versionadded:: 3.14
     The variable ``GET_PREREQUISITES_VERBOSE`` can be set to true before calling
-    this function to enable verbose output.
+    this command to enable verbose output.
 
 .. command:: list_prerequisites
 
+  Prints a message listing the prerequisites of the specified target:
+
   .. code-block:: cmake
 
     list_prerequisites(<target> [<recurse> [<exclude-system> [<verbose>]]])
 
-  Prints a message listing the prerequisites of ``<target>``.
-
   The arguments are:
 
   ``<target>``
@@ -107,15 +115,15 @@
 
 .. command:: list_prerequisites_by_glob
 
+  Prints the prerequisites of shared library and executable files matching a
+  globbing pattern:
+
   .. code-block:: cmake
 
     list_prerequisites_by_glob(<GLOB|GLOB_RECURSE>
                                <glob-exp>
                                [<optional-args>...])
 
-  Prints the prerequisites of shared library and executable files matching a
-  globbing pattern.
-
   The arguments are:
 
   ``GLOB`` or ``GLOB_RECURSE``
@@ -131,44 +139,56 @@
 
 .. command:: gp_append_unique
 
+  Appends the value to the list only if it is not already in the list:
+
   .. code-block:: cmake
 
     gp_append_unique(<list-var> <value>)
 
-  Appends ``<value>`` to the list variable ``<list-var>`` only if the value is
-  not already in the list.
+  The arguments are:
+
+  ``<value>``
+    The value to be appended to the list.
+  ``<list-var>``
+    The list variable name that will have the value appended only if it is
+    not already in the list.
 
 .. command:: is_file_executable
 
+  Checks if given file is a binary executable:
+
   .. code-block:: cmake
 
     is_file_executable(<file> <result-var>)
 
-  Sets ``<result-var>`` to 1 if ``<file>`` is a binary executable; otherwise
-  sets it to 0.
+  This command sets the ``<result-var>`` to 1 if ``<file>`` is a binary
+  executable; otherwise it sets it to 0.
 
 .. command:: gp_item_default_embedded_path
 
+  Determines the reference path for the specified item:
+
   .. code-block:: cmake
 
     gp_item_default_embedded_path(<item> <default-embedded-path-var>)
 
-  Determines the reference path for ``<item>`` when it is embedded inside a
-  bundle and stores it to a variable ``<default-embedded-path-var>``.
+  This command determines the reference path for ``<item>`` when it is
+  embedded inside a bundle and stores it to a variable
+  ``<default-embedded-path-var>``.
 
-  Projects can override this function by defining a custom
-  ``gp_item_default_embedded_path_override()`` function.
+  Projects can override this command by defining a custom
+  ``gp_item_default_embedded_path_override()`` command.
 
 .. command:: gp_resolve_item
 
+  Resolves a given item into an existing full path file and stores it to a
+  variable:
+
   .. code-block:: cmake
 
     gp_resolve_item(<context> <item> <exepath> <dirs> <resolved-item-var>
                     [<rpaths>])
 
-  Resolves a given ``<item>`` into an existing full path file and stores it to a
-  ``<resolved-item-var>`` variable.
-
   The arguments are:
 
   ``<context>``
@@ -187,18 +207,21 @@
   ``<rpaths>``
     See the argument description in :command:`get_prerequisites`.
 
-  Projects can override this function by defining a custom
-  ``gp_resolve_item_override()`` function.
+  Projects can override this command by defining a custom
+  ``gp_resolve_item_override()`` command.
 
 .. command:: gp_resolved_file_type
 
+  Determines the type of a given file:
+
   .. code-block:: cmake
 
     gp_resolved_file_type(<original-file> <file> <exepath> <dirs> <type-var>
                           [<rpaths>])
 
-  Determines the type of ``<file>`` with respect to ``<original-file>``. The
-  resulting type of prerequisite is stored in the ``<type-var>`` variable.
+  This command determines the type of ``<file>`` with respect to the
+  ``<original-file>``.  The resulting type of prerequisite is stored in the
+  ``<type-var>`` variable.
 
   Use ``<exepath>`` and ``<dirs>`` if necessary to resolve non-absolute
   ``<file>`` values -- but only for non-embedded items.
@@ -213,17 +236,20 @@
   * ``embedded``
   * ``other``
 
-  Projects can override this function by defining a custom
-  ``gp_resolved_file_type_override()`` function.
+  Projects can override this command by defining a custom
+  ``gp_resolved_file_type_override()`` command.
 
 .. command:: gp_file_type
 
+  Determines the type of a given file:
+
   .. code-block:: cmake
 
     gp_file_type(<original-file> <file> <type-var>)
 
-  Determines the type of ``<file>`` with respect to ``<original-file>``. The
-  resulting type of prerequisite is stored in the ``<type-var>`` variable.
+  This command determines the type of ``<file>`` with respect to the
+  ``<original-file>``.  The resulting type of prerequisite is stored in the
+  ``<type-var>`` variable.
 
   The ``<type-var>`` variable will be set to one of the following values:
 
@@ -235,6 +261,9 @@
 Examples
 ^^^^^^^^
 
+Example: Basic Usage
+""""""""""""""""""""
+
 Printing all dependencies of a shared library, including system libraries, with
 verbose output:
 
@@ -242,6 +271,25 @@
 
   include(GetPrerequisites)
   list_prerequisites("path/to/libfoo.dylib" 1 0 1)
+
+Example: Upgrading Code
+"""""""""""""""""""""""
+
+For example:
+
+.. code-block:: cmake
+
+  include(GetPrerequisites)
+  # ...
+  gp_append_unique(keys "${key}")
+
+the ``gp_append_unique()`` can be in new code replaced with:
+
+.. code-block:: cmake
+
+  if(NOT key IN_LIST keys)
+    list(APPEND keys "${key}")
+  endif()
 #]=======================================================================]
 
 function(gp_append_unique list_var value)
diff --git a/Modules/GoogleTestAddTests.cmake b/Modules/GoogleTestAddTests.cmake
index 3af16f8..d376af1 100644
--- a/Modules/GoogleTestAddTests.cmake
+++ b/Modules/GoogleTestAddTests.cmake
@@ -43,6 +43,241 @@
   endif()
 endfunction()
 
+macro(write_test_to_file)
+  # Store the gtest test name before messing with these strings
+  set(gtest_name ${current_test_suite}.${current_test_name})
+
+  set(pretty_test_suite ${current_test_suite})
+  set(pretty_test_name ${current_test_name})
+
+  # Handle disabled tests
+  set(maybe_DISABLED "")
+  if(pretty_test_suite MATCHES "^DISABLED_" OR pretty_test_name MATCHES "^DISABLED_")
+    set(maybe_DISABLED DISABLED YES)
+    string(REGEX REPLACE "^DISABLED_" "" pretty_test_suite "${pretty_test_suite}")
+    string(REGEX REPLACE "^DISABLED_" "" pretty_test_name "${pretty_test_name}")
+  endif()
+
+  if (NOT current_test_value_param STREQUAL "" AND NOT arg_NO_PRETTY_VALUES)
+    # Remove value param name, if any, from test name
+    string(REGEX REPLACE "^(.+)/.+$" "\\1" pretty_test_name "${pretty_test_name}")
+    set(pretty_test_name "${pretty_test_name}/${current_test_value_param}")
+  endif()
+
+  if(NOT current_test_type_param STREQUAL "")
+    # Parse type param name from suite name
+    if(pretty_test_suite MATCHES "^(.+)/(.+)$")
+      set(pretty_test_suite "${CMAKE_MATCH_1}")
+      set(current_type_param_name "${CMAKE_MATCH_2}")
+    else()
+      set(current_type_param_name "")
+    endif()
+    if (NOT arg_NO_PRETTY_TYPES)
+      string(APPEND pretty_test_name  "<${current_test_type_param}>")
+    elseif(NOT current_type_param_name STREQUAL "")
+        string(APPEND pretty_test_name "<${current_type_param_name}>")
+    endif()
+  endif()
+
+  set(test_name_template "@prefix@@pretty_test_suite@.@pretty_test_name@@suffix@")
+  string(CONFIGURE "${test_name_template}" testname)
+
+  if(NOT "${arg_TEST_XML_OUTPUT_DIR}" STREQUAL "")
+    set(TEST_XML_OUTPUT_PARAM "--gtest_output=xml:${arg_TEST_XML_OUTPUT_DIR}/${prefix}${gtest_name}${suffix}.xml")
+  else()
+    set(TEST_XML_OUTPUT_PARAM "")
+  endif()
+
+  # unescape []
+  if(open_sb)
+    string(REPLACE "${open_sb}" "[" testname "${testname}")
+  endif()
+  if(close_sb)
+    string(REPLACE "${close_sb}" "]" testname "${testname}")
+  endif()
+  set(guarded_testname "${open_guard}${testname}${close_guard}")
+  # Add to script. Do not use add_command() here because it messes up the
+  # handling of empty values when forwarding arguments, and we need to
+  # preserve those carefully for arg_TEST_EXECUTOR and arg_EXTRA_ARGS.
+  string(APPEND script "add_test(${guarded_testname} ${launcherArgs}")
+  foreach(arg IN ITEMS
+    "${arg_TEST_EXECUTABLE}"
+    "--gtest_filter=${gtest_name}"
+    "--gtest_also_run_disabled_tests"
+    ${TEST_XML_OUTPUT_PARAM}
+  )
+
+    if(arg MATCHES "[^-./:a-zA-Z0-9_]")
+      string(APPEND script " [==[${arg}]==]")
+    else()
+      string(APPEND script " ${arg}")
+    endif()
+  endforeach()
+
+  if(arg_TEST_EXTRA_ARGS)
+    list(JOIN arg_TEST_EXTRA_ARGS "]==] [==[" extra_args)
+    string(APPEND script " [==[${extra_args}]==]")
+  endif()
+  string(APPEND script ")\n")
+
+  set(maybe_LOCATION "")
+  if(NOT current_test_file STREQUAL "" AND NOT current_test_line STREQUAL "")
+    set(maybe_LOCATION DEF_SOURCE_LINE "${current_test_file}:${current_test_line}")
+  endif()
+
+  add_command(set_tests_properties
+    "${guarded_testname}"
+    PROPERTIES
+      ${maybe_DISABLED}
+      ${maybe_LOCATION}
+      WORKING_DIRECTORY "${arg_TEST_WORKING_DIR}"
+      SKIP_REGULAR_EXPRESSION "\\[  SKIPPED \\]"
+      ${arg_TEST_PROPERTIES}
+  )
+
+  # possibly unbalanced square brackets render lists invalid so skip such
+  # tests in ${arg_TEST_LIST}
+  if(NOT "${testname}" MATCHES [=[(\[|\])]=])
+    # escape ;
+    string(REPLACE [[;]] [[\\;]] testname "${testname}")
+    list(APPEND tests_buffer "${testname}")
+    list(LENGTH tests_buffer tests_buffer_length)
+    if(tests_buffer_length GREATER "250")
+      # Chunk updates to the final "tests" variable, keeping the
+      # "tests_buffer" variable that we append each test to relatively
+      # small. This mitigates worsening performance impacts for the
+      # corner case of having many thousands of tests.
+      list(APPEND tests "${tests_buffer}")
+      set(tests_buffer "")
+    endif()
+  endif()
+
+  # If we've built up a sizable script so far, write it out as a chunk now
+  # so we don't accumulate a massive string to write at the end
+  string(LENGTH "${script}" script_len)
+  if(${script_len} GREATER "50000")
+    file(APPEND "${arg_CTEST_FILE}" "${script}")
+    set(script "")
+  endif()
+endmacro()
+
+macro(parse_tests_from_output)
+  generate_testname_guards("${output}" open_guard close_guard)
+  escape_square_brackets("${output}" "[" "__osb" open_sb output)
+  escape_square_brackets("${output}" "]" "__csb" close_sb output)
+
+  # Preserve semicolon in test-parameters
+  string(REPLACE [[;]] [[\;]] output "${output}")
+  string(REPLACE "\n" ";" output "${output}")
+
+  # Command line output doesn't contain information about the file and line number of the tests
+  set(current_test_file "")
+  set(current_test_line "")
+
+  # Parse output
+  foreach(line ${output})
+    # Skip header
+    if(line MATCHES "gtest_main\\.cc")
+      continue()
+    endif()
+
+    if(line STREQUAL "")
+      continue()
+    endif()
+
+    # Do we have a module name or a test name?
+    if(NOT line MATCHES "^  ")
+      set(current_test_type_param "")
+
+      # Module; remove trailing '.' to get just the name...
+      string(REGEX REPLACE "\\.( *#.*)?$" "" current_test_suite "${line}")
+      if(line MATCHES "# *TypeParam = (.*)$")
+        set(current_test_type_param "${CMAKE_MATCH_1}")
+      endif()
+    else()
+      string(STRIP "${line}" test)
+      string(REGEX REPLACE " ( *#.*)?$" "" current_test_name "${test}")
+
+      set(current_test_value_param "")
+      if(line MATCHES "# *GetParam\\(\\) = (.*)$")
+        set(current_test_value_param "${CMAKE_MATCH_1}")
+      endif()
+
+      write_test_to_file()
+    endif()
+  endforeach()
+endmacro()
+
+macro(get_json_member_with_default json_variable member_name out_variable)
+  string(JSON ${out_variable}
+    ERROR_VARIABLE error_param
+    GET "${${json_variable}}" "${member_name}"
+  )
+  if(error_param)
+    # Member not present
+    set(${out_variable} "")
+  endif()
+endmacro()
+
+macro(parse_tests_from_json json_file)
+  if(NOT EXISTS "${json_file}")
+    message(FATAL_ERROR "Missing expected JSON file with test list: ${json_file}")
+  endif()
+
+  file(READ "${json_file}" test_json)
+  string(JSON test_suites_json GET "${test_json}" "testsuites")
+
+  # Return if there are no testsuites
+  string(JSON len_test_suites LENGTH "${test_suites_json}")
+  if(len_test_suites LESS_EQUAL 0)
+    return()
+  endif()
+
+  set(open_sb)
+  set(close_sb)
+
+  math(EXPR upper_limit_test_suite_range "${len_test_suites} - 1")
+
+  foreach(index_test_suite RANGE ${upper_limit_test_suite_range})
+    string(JSON test_suite_json GET "${test_suites_json}" ${index_test_suite})
+
+    # "suite" is expected to be set in write_test_to_file(). When parsing the
+    # plain text output, "suite" is expected to be the original suite name
+    # before accounting for pretty names. This may be used to construct the
+    # name of XML output results files.
+    string(JSON current_test_suite GET "${test_suite_json}" "name")
+    string(JSON tests_json GET "${test_suite_json}" "testsuite")
+
+    # Skip test suites without tests
+    string(JSON len_tests LENGTH "${tests_json}")
+    if(len_tests LESS_EQUAL 0)
+      continue()
+    endif()
+
+    math(EXPR upper_limit_test_range "${len_tests} - 1")
+    foreach(index_test RANGE ${upper_limit_test_range})
+      string(JSON test_json GET "${tests_json}" ${index_test})
+
+      string(JSON len_test_parameters LENGTH "${test_json}")
+      if(len_test_parameters LESS_EQUAL 0)
+        continue()
+      endif()
+
+      get_json_member_with_default(test_json "name" current_test_name)
+      get_json_member_with_default(test_json "file" current_test_file)
+      get_json_member_with_default(test_json "line" current_test_line)
+      get_json_member_with_default(test_json "value_param" current_test_value_param)
+      get_json_member_with_default(test_json "type_param" current_test_type_param)
+
+      generate_testname_guards(
+        "${current_test_suite}${current_test_name}${current_test_value_param}${current_test_type_param}"
+        open_guard close_guard
+      )
+      write_test_to_file()
+    endforeach()
+  endforeach()
+endmacro()
+
 function(gtest_discover_tests_impl)
 
   set(options "")
@@ -74,19 +309,15 @@
   set(prefix "${arg_TEST_PREFIX}")
   set(suffix "${arg_TEST_SUFFIX}")
   set(script)
-  set(suite)
   set(tests)
   set(tests_buffer "")
 
   # If a file at ${arg_CTEST_FILE} already exists, we overwrite it.
-  # For performance reasons, we write to this file in chunks, and this variable
-  # is updated to APPEND after the first write.
-  set(file_write_mode WRITE)
+  file(REMOVE "${arg_CTEST_FILE}")
 
+  set(filter)
   if(arg_TEST_FILTER)
     set(filter "--gtest_filter=${arg_TEST_FILTER}")
-  else()
-    set(filter)
   endif()
 
   # CMP0178 has already been handled in gtest_discover_tests(), so we only need
@@ -113,15 +344,25 @@
     set(discovery_extra_args "[==[${discovery_extra_args}]==]")
   endif()
 
+  set(json_file "${arg_TEST_WORKING_DIR}/cmake_test_discovery.json")
+
+  # Remove json file to make sure we don't pick up an outdated one
+  file(REMOVE "${json_file}")
+
   cmake_language(EVAL CODE
     "execute_process(
-      COMMAND ${launcherArgs} [==[${arg_TEST_EXECUTABLE}]==] --gtest_list_tests ${filter} ${discovery_extra_args}
+      COMMAND ${launcherArgs} [==[${arg_TEST_EXECUTABLE}]==]
+        --gtest_list_tests
+        [==[--gtest_output=json:${json_file}]==]
+        ${filter}
+        ${discovery_extra_args}
       WORKING_DIRECTORY [==[${arg_TEST_WORKING_DIR}]==]
       TIMEOUT ${arg_TEST_DISCOVERY_TIMEOUT}
       OUTPUT_VARIABLE output
       RESULT_VARIABLE result
     )"
   )
+
   if(NOT ${result} EQUAL 0)
     string(REPLACE "\n" "\n    " output "${output}")
     if(arg_TEST_EXECUTOR)
@@ -139,124 +380,21 @@
     )
   endif()
 
-  generate_testname_guards("${output}" open_guard close_guard)
-  escape_square_brackets("${output}" "[" "__osb" open_sb output)
-  escape_square_brackets("${output}" "]" "__csb" close_sb output)
-  # Preserve semicolon in test-parameters
-  string(REPLACE [[;]] [[\;]] output "${output}")
-  string(REPLACE "\n" ";" output "${output}")
+  if(EXISTS "${json_file}")
+    parse_tests_from_json("${json_file}")
+  else()
+    # gtest < 1.8.1, and all gtest compiled with GTEST_HAS_FILE_SYSTEM=0, don't
+    # recognize the --gtest_output=json option, and issue a warning or error on
+    # stdout about it being unrecognized, but still return an exit code 0 for
+    # success. All versions report the test list on stdout whether
+    # --gtest_output=json is recognized or not.
 
-  # Parse output
-  foreach(line ${output})
-    # Skip header
-    if(NOT line MATCHES "gtest_main\\.cc")
-      # Do we have a module name or a test name?
-      if(NOT line MATCHES "^  ")
-        # Module; remove trailing '.' to get just the name...
-        string(REGEX REPLACE "\\.( *#.*)?$" "" suite "${line}")
-        if(line MATCHES "#")
-          string(REGEX REPLACE "/[0-9].*" "" pretty_suite "${line}")
-          if(NOT arg_NO_PRETTY_TYPES)
-            string(REGEX REPLACE ".*/[0-9]+[ .#]+TypeParam = (.*)" "\\1" type_parameter "${line}")
-          else()
-            string(REGEX REPLACE ".*/([0-9]+)[ .#]+TypeParam = .*" "\\1" type_parameter "${line}")
-          endif()
-          set(test_name_template "@prefix@@pretty_suite@.@pretty_test@<@type_parameter@>@suffix@")
-        else()
-          set(pretty_suite "${suite}")
-          set(test_name_template "@prefix@@pretty_suite@.@pretty_test@@suffix@")
-        endif()
-        string(REGEX REPLACE "^DISABLED_" "" pretty_suite "${pretty_suite}")
-      else()
-        string(STRIP "${line}" test)
-        if(test MATCHES "#" AND NOT arg_NO_PRETTY_VALUES)
-          string(REGEX REPLACE "/[0-9]+[ #]+GetParam\\(\\) = " "/" pretty_test "${test}")
-        else()
-          string(REGEX REPLACE " +#.*" "" pretty_test "${test}")
-        endif()
-        string(REGEX REPLACE "^DISABLED_" "" pretty_test "${pretty_test}")
-        string(REGEX REPLACE " +#.*" "" test "${test}")
-        if(NOT "${arg_TEST_XML_OUTPUT_DIR}" STREQUAL "")
-          set(TEST_XML_OUTPUT_PARAM "--gtest_output=xml:${arg_TEST_XML_OUTPUT_DIR}/${prefix}${suite}.${test}${suffix}.xml")
-        else()
-          unset(TEST_XML_OUTPUT_PARAM)
-        endif()
-
-        string(CONFIGURE "${test_name_template}" testname)
-        # unescape []
-        if(open_sb)
-          string(REPLACE "${open_sb}" "[" testname "${testname}")
-        endif()
-        if(close_sb)
-          string(REPLACE "${close_sb}" "]" testname "${testname}")
-        endif()
-        set(guarded_testname "${open_guard}${testname}${close_guard}")
-
-        # Add to script. Do not use add_command() here because it messes up the
-        # handling of empty values when forwarding arguments, and we need to
-        # preserve those carefully for arg_TEST_EXECUTOR and arg_EXTRA_ARGS.
-        string(APPEND script "add_test(${guarded_testname} ${launcherArgs}")
-        foreach(arg IN ITEMS
-          "${arg_TEST_EXECUTABLE}"
-          "--gtest_filter=${suite}.${test}"
-          "--gtest_also_run_disabled_tests"
-          ${TEST_XML_OUTPUT_PARAM}
-          )
-          if(arg MATCHES "[^-./:a-zA-Z0-9_]")
-            string(APPEND script " [==[${arg}]==]")
-          else()
-            string(APPEND script " ${arg}")
-          endif()
-        endforeach()
-        if(arg_TEST_EXTRA_ARGS)
-          list(JOIN arg_TEST_EXTRA_ARGS "]==] [==[" extra_args)
-          string(APPEND script " [==[${extra_args}]==]")
-        endif()
-        string(APPEND script ")\n")
-
-        set(maybe_disabled "")
-        if(suite MATCHES "^DISABLED_" OR test MATCHES "^DISABLED_")
-          set(maybe_disabled DISABLED TRUE)
-        endif()
-
-        add_command(set_tests_properties
-          "${guarded_testname}"
-          PROPERTIES
-          ${maybe_disabled}
-          WORKING_DIRECTORY "${arg_TEST_WORKING_DIR}"
-          SKIP_REGULAR_EXPRESSION "\\[  SKIPPED \\]"
-          ${arg_TEST_PROPERTIES}
-        )
-
-        # possibly unbalanced square brackets render lists invalid so skip such
-        # tests in ${arg_TEST_LIST}
-        if(NOT "${testname}" MATCHES [=[(\[|\])]=])
-          # escape ;
-          string(REPLACE [[;]] [[\\;]] testname "${testname}")
-          list(APPEND tests_buffer "${testname}")
-          list(LENGTH tests_buffer tests_buffer_length)
-          if(tests_buffer_length GREATER "250")
-            # Chunk updates to the final "tests" variable, keeping the
-            # "tests_buffer" variable that we append each test to relatively
-            # small. This mitigates worsening performance impacts for the
-            # corner case of having many thousands of tests.
-            list(APPEND tests "${tests_buffer}")
-            set(tests_buffer "")
-          endif()
-        endif()
-      endif()
-
-      # If we've built up a sizable script so far, write it out as a chunk now
-      # so we don't accumulate a massive string to write at the end
-      string(LENGTH "${script}" script_len)
-      if(${script_len} GREATER "50000")
-        file(${file_write_mode} "${arg_CTEST_FILE}" "${script}")
-        set(file_write_mode APPEND)
-        set(script "")
-      endif()
-
-    endif()
-  endforeach()
+    # NOTE: Because we are calling a macro, we don't want to pass "output" as
+    # an argument because it messes up the contents passed through due to the
+    # different escaping, etc. that gets applied. We rely on it picking up the
+    # "output" variable we have already set here.
+    parse_tests_from_output()
+  endif()
 
   if(NOT tests_buffer STREQUAL "")
     list(APPEND tests "${tests_buffer}")
@@ -267,8 +405,7 @@
   add_command(set "" ${arg_TEST_LIST} "${tests}")
 
   # Write remaining content to the CTest script
-  file(${file_write_mode} "${arg_CTEST_FILE}" "${script}")
-
+  file(APPEND "${arg_CTEST_FILE}" "${script}")
 endfunction()
 
 if(CMAKE_SCRIPT_MODE_FILE)
diff --git a/Modules/Internal/CMakeParseCompilerArchitectureId.cmake b/Modules/Internal/CMakeParseCompilerArchitectureId.cmake
index 9200158..e5ee90e 100644
--- a/Modules/Internal/CMakeParseCompilerArchitectureId.cmake
+++ b/Modules/Internal/CMakeParseCompilerArchitectureId.cmake
@@ -47,6 +47,8 @@
     set(ARCHITECTURE_ID "riscv64")
   elseif(_dumpmachine_triple MATCHES "^riscv32-")
     set(ARCHITECTURE_ID "riscv32")
+  elseif(_dumpmachine_triple MATCHES "^sunway-")
+    set(ARCHITECTURE_ID "sw_64")
   elseif(_dumpmachine_triple MATCHES "^s390x-")
     set(ARCHITECTURE_ID "s390x")
   elseif(_dumpmachine_triple MATCHES "^s390-")
diff --git a/Modules/MacroAddFileDependencies.cmake b/Modules/MacroAddFileDependencies.cmake
index 9dee09d..0c65c46 100644
--- a/Modules/MacroAddFileDependencies.cmake
+++ b/Modules/MacroAddFileDependencies.cmake
@@ -6,24 +6,38 @@
 ------------------------
 
 .. deprecated:: 3.14
+  Do not use this module in new code.
+
+  Instead use the :command:`set_property` command to append to the
+  :prop_sf:`OBJECT_DEPENDS` source file property directly:
+
+  .. code-block:: cmake
+
+    set_property(SOURCE <source> APPEND PROPERTY OBJECT_DEPENDS <files>...)
+
+Load this module in a CMake project with:
 
 .. code-block:: cmake
 
-  macro_add_file_dependencies(<source> <files>...)
+  include(MacroAddFileDependencies)
 
-Do not use this command in new code.  It is just a wrapper around:
+Commands
+^^^^^^^^
 
-.. code-block:: cmake
+This module provides the following command:
 
-  set_property(SOURCE <source> APPEND PROPERTY OBJECT_DEPENDS <files>...)
+.. command:: macro_add_file_dependencies
 
-Instead use the :command:`set_property` command to append to the
-:prop_sf:`OBJECT_DEPENDS` source file property directly.
+  Adds dependencies to a source file:
 
+  .. code-block:: cmake
+
+    macro_add_file_dependencies(<source> <files>...)
+
+  This command adds the given ``<files>`` to the dependencies of file
+  ``<source>``.
 #]=======================================================================]
 
-macro (MACRO_ADD_FILE_DEPENDENCIES _file)
-
+macro(MACRO_ADD_FILE_DEPENDENCIES _file)
   set_property(SOURCE "${_file}" APPEND PROPERTY OBJECT_DEPENDS "${ARGN}")
-
-endmacro ()
+endmacro()
diff --git a/Modules/Platform/AIX.cmake b/Modules/Platform/AIX.cmake
index dcc9837..a8561a0 100644
--- a/Modules/Platform/AIX.cmake
+++ b/Modules/Platform/AIX.cmake
@@ -3,7 +3,7 @@
 set(CMAKE_SHARED_LIBRARY_ARCHIVE_SUFFIX ".a")   # .a
 set(CMAKE_AIX_IMPORT_FILE_PREFIX "")
 set(CMAKE_AIX_IMPORT_FILE_SUFFIX ".imp")
-set(CMAKE_DL_LIBS "-lld")
+set(CMAKE_DL_LIBS "ld")
 
 # RPATH support on AIX is called libpath.  By default the runtime
 # libpath is paths specified by -L followed by /usr/lib and /lib.  In
diff --git a/Modules/Platform/Emscripten-Clang-C.cmake b/Modules/Platform/Emscripten-Clang-C.cmake
new file mode 100644
index 0000000..1b6b2ab
--- /dev/null
+++ b/Modules/Platform/Emscripten-Clang-C.cmake
@@ -0,0 +1,3 @@
+include(Platform/Emscripten-Clang)
+
+__emscripten_clang(C)
diff --git a/Modules/Platform/Emscripten-Clang-CXX.cmake b/Modules/Platform/Emscripten-Clang-CXX.cmake
new file mode 100644
index 0000000..32b913e
--- /dev/null
+++ b/Modules/Platform/Emscripten-Clang-CXX.cmake
@@ -0,0 +1,3 @@
+include(Platform/Emscripten-Clang)
+
+__emscripten_clang(CXX)
diff --git a/Modules/Platform/Emscripten-Clang.cmake b/Modules/Platform/Emscripten-Clang.cmake
new file mode 100644
index 0000000..88cb197
--- /dev/null
+++ b/Modules/Platform/Emscripten-Clang.cmake
@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include_guard()
+
+macro(__emscripten_clang lang)
+  set(CMAKE_SHARED_LIBRARY_SONAME_${lang}_FLAG "-Wl,-soname,")
+  set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-sSIDE_MODULE")
+
+  set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
+  set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_OBJECTS 1)
+  set(CMAKE_${lang}_USE_RESPONSE_FILE_FOR_INCLUDES 1)
+  set(CMAKE_${lang}_COMPILE_OBJECT
+    "<CMAKE_${lang}_COMPILER> -c <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -fPIC")
+  set(CMAKE_${lang}_LINK_EXECUTABLE
+    "<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -sMAIN_MODULE")
+endmacro()
diff --git a/Modules/Platform/Emscripten-Initialize.cmake b/Modules/Platform/Emscripten-Initialize.cmake
new file mode 100644
index 0000000..3117e05
--- /dev/null
+++ b/Modules/Platform/Emscripten-Initialize.cmake
@@ -0,0 +1,2 @@
+set(EMSCRIPTEN 1)
+set(UNIX 1)
diff --git a/Modules/Platform/Emscripten.cmake b/Modules/Platform/Emscripten.cmake
new file mode 100644
index 0000000..8157d47
--- /dev/null
+++ b/Modules/Platform/Emscripten.cmake
@@ -0,0 +1,6 @@
+set(CMAKE_SHARED_LIBRARY_LINK_C_WITH_RUNTIME_PATH ON)
+
+set(CMAKE_SHARED_LIBRARY_SUFFIX ".wasm")
+set(CMAKE_EXECUTABLE_SUFFIX ".js")
+
+set(CMAKE_DL_LIBS "")
diff --git a/Modules/Platform/FreeBSD-Clang-ASM.cmake b/Modules/Platform/FreeBSD-Clang-ASM.cmake
new file mode 100644
index 0000000..d9557d6
--- /dev/null
+++ b/Modules/Platform/FreeBSD-Clang-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/FreeBSD-GNU-ASM)
diff --git a/Modules/Platform/FreeBSD-Clang-C.cmake b/Modules/Platform/FreeBSD-Clang-C.cmake
new file mode 100644
index 0000000..bf7349b
--- /dev/null
+++ b/Modules/Platform/FreeBSD-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/FreeBSD-GNU-C)
diff --git a/Modules/Platform/FreeBSD-Clang-CXX.cmake b/Modules/Platform/FreeBSD-Clang-CXX.cmake
new file mode 100644
index 0000000..ceed6b6
--- /dev/null
+++ b/Modules/Platform/FreeBSD-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/FreeBSD-GNU-CXX)
diff --git a/Modules/Platform/FreeBSD-GNU-ASM.cmake b/Modules/Platform/FreeBSD-GNU-ASM.cmake
new file mode 100644
index 0000000..8da5100
--- /dev/null
+++ b/Modules/Platform/FreeBSD-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/FreeBSD-GNU)
+__freebsd_compiler_gnu(ASM)
diff --git a/Modules/Platform/FreeBSD-GNU-C.cmake b/Modules/Platform/FreeBSD-GNU-C.cmake
new file mode 100644
index 0000000..f19c60b
--- /dev/null
+++ b/Modules/Platform/FreeBSD-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/FreeBSD-GNU)
+__freebsd_compiler_gnu(C)
diff --git a/Modules/Platform/FreeBSD-GNU-CXX.cmake b/Modules/Platform/FreeBSD-GNU-CXX.cmake
new file mode 100644
index 0000000..9589dad
--- /dev/null
+++ b/Modules/Platform/FreeBSD-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/FreeBSD-GNU)
+__freebsd_compiler_gnu(CXX)
diff --git a/Modules/Platform/FreeBSD-GNU-Fortran.cmake b/Modules/Platform/FreeBSD-GNU-Fortran.cmake
new file mode 100644
index 0000000..d37a355
--- /dev/null
+++ b/Modules/Platform/FreeBSD-GNU-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/FreeBSD-GNU)
+__freebsd_compiler_gnu(Fortran)
diff --git a/Modules/Platform/FreeBSD-GNU.cmake b/Modules/Platform/FreeBSD-GNU.cmake
new file mode 100644
index 0000000..36ba126
--- /dev/null
+++ b/Modules/Platform/FreeBSD-GNU.cmake
@@ -0,0 +1,16 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include_guard()
+
+macro(__freebsd_compiler_gnu lang)
+  # linker selection
+  set(CMAKE_${lang}_USING_LINKER_SYSTEM "")
+  set(CMAKE_${lang}_USING_LINKER_LLD "-fuse-ld=lld")
+  set(CMAKE_${lang}_USING_LINKER_BFD "-fuse-ld=bfd")
+  set(CMAKE_${lang}_USING_LINKER_GOLD "-fuse-ld=gold")
+  if(NOT CMAKE_${lang}_COMPILER_ID STREQUAL "GNU"
+      OR CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
+    set(CMAKE_${lang}_USING_LINKER_MOLD "-fuse-ld=mold")
+  endif()
+endmacro()
diff --git a/Modules/Platform/Linker/Emscripten-C.cmake b/Modules/Platform/Linker/Emscripten-C.cmake
new file mode 100644
index 0000000..dfef6a3
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-C.cmake
@@ -0,0 +1,4 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(Platform/Linker/Emscripten-LLD-C)
diff --git a/Modules/Platform/Linker/Emscripten-CXX.cmake b/Modules/Platform/Linker/Emscripten-CXX.cmake
new file mode 100644
index 0000000..90bb820
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-CXX.cmake
@@ -0,0 +1,4 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(Platform/Linker/Emscripten-LLD-CXX)
diff --git a/Modules/Platform/Linker/Emscripten-LLD-C.cmake b/Modules/Platform/Linker/Emscripten-LLD-C.cmake
new file mode 100644
index 0000000..448d7cc
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-LLD-C.cmake
@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(Platform/Linker/Emscripten-LLD)
+
+__emscripten_linker_lld(C)
diff --git a/Modules/Platform/Linker/Emscripten-LLD-CXX.cmake b/Modules/Platform/Linker/Emscripten-LLD-CXX.cmake
new file mode 100644
index 0000000..63d71b4
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-LLD-CXX.cmake
@@ -0,0 +1,6 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include(Platform/Linker/Emscripten-LLD)
+
+__emscripten_linker_lld(CXX)
diff --git a/Modules/Platform/Linker/Emscripten-LLD.cmake b/Modules/Platform/Linker/Emscripten-LLD.cmake
new file mode 100644
index 0000000..4c02cf7
--- /dev/null
+++ b/Modules/Platform/Linker/Emscripten-LLD.cmake
@@ -0,0 +1,11 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+# This module is shared by multiple languages; use include blocker.
+include_guard()
+
+macro(__emscripten_linker_lld lang)
+  set(CMAKE_${lang}_LINK_LIBRARY_USING_WHOLE_ARCHIVE "-Wl,--whole-archive" "<LINK_ITEM>" "-Wl,--no-whole-archive")
+  set(CMAKE_${lang}_LINK_LIBRARY_USING_WHOLE_ARCHIVE_SUPPORTED TRUE)
+  set(CMAKE_${lang}_LINK_LIBRARY_WHOLE_ARCHIVE_ATTRIBUTES LIBRARY_TYPE=STATIC DEDUPLICATION=YES OVERRIDE=DEFAULT)
+endmacro()
diff --git a/Modules/Platform/MirBSD-GNU-ASM.cmake b/Modules/Platform/MirBSD-GNU-ASM.cmake
new file mode 100644
index 0000000..812fc96
--- /dev/null
+++ b/Modules/Platform/MirBSD-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/MirBSD-GNU)
+__mirbsd_compiler_gnu(ASM)
diff --git a/Modules/Platform/MirBSD-GNU-C.cmake b/Modules/Platform/MirBSD-GNU-C.cmake
new file mode 100644
index 0000000..c1c66d7
--- /dev/null
+++ b/Modules/Platform/MirBSD-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/MirBSD-GNU)
+__mirbsd_compiler_gnu(C)
diff --git a/Modules/Platform/MirBSD-GNU-CXX.cmake b/Modules/Platform/MirBSD-GNU-CXX.cmake
new file mode 100644
index 0000000..bf02157
--- /dev/null
+++ b/Modules/Platform/MirBSD-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/MirBSD-GNU)
+__mirbsd_compiler_gnu(CXX)
diff --git a/Modules/Platform/MirBSD-GNU-Fortran.cmake b/Modules/Platform/MirBSD-GNU-Fortran.cmake
new file mode 100644
index 0000000..52ba2cb
--- /dev/null
+++ b/Modules/Platform/MirBSD-GNU-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/MirBSD-GNU)
+__mirbsd_compiler_gnu(Fortran)
diff --git a/Modules/Platform/MirBSD-GNU.cmake b/Modules/Platform/MirBSD-GNU.cmake
new file mode 100644
index 0000000..9025c36
--- /dev/null
+++ b/Modules/Platform/MirBSD-GNU.cmake
@@ -0,0 +1,7 @@
+include_guard()
+
+include(Platform/OpenBSD-GNU)
+
+macro(__mirbsd_compiler_gnu lang)
+  __openbsd_compiler_gnu(${lang})
+endmacro()
diff --git a/Modules/Platform/NetBSD-Clang-ASM.cmake b/Modules/Platform/NetBSD-Clang-ASM.cmake
new file mode 100644
index 0000000..b7c7b2d
--- /dev/null
+++ b/Modules/Platform/NetBSD-Clang-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/NetBSD-GNU-ASM)
diff --git a/Modules/Platform/NetBSD-Clang-C.cmake b/Modules/Platform/NetBSD-Clang-C.cmake
new file mode 100644
index 0000000..86b6a01
--- /dev/null
+++ b/Modules/Platform/NetBSD-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/NetBSD-GNU-C)
diff --git a/Modules/Platform/NetBSD-Clang-CXX.cmake b/Modules/Platform/NetBSD-Clang-CXX.cmake
new file mode 100644
index 0000000..b1a5d10
--- /dev/null
+++ b/Modules/Platform/NetBSD-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/NetBSD-GNU-CXX)
diff --git a/Modules/Platform/NetBSD-GNU-ASM.cmake b/Modules/Platform/NetBSD-GNU-ASM.cmake
new file mode 100644
index 0000000..6b7d012
--- /dev/null
+++ b/Modules/Platform/NetBSD-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/NetBSD-GNU)
+__netbsd_compiler_gnu(ASM)
diff --git a/Modules/Platform/NetBSD-GNU-C.cmake b/Modules/Platform/NetBSD-GNU-C.cmake
new file mode 100644
index 0000000..815644a
--- /dev/null
+++ b/Modules/Platform/NetBSD-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/NetBSD-GNU)
+__netbsd_compiler_gnu(C)
diff --git a/Modules/Platform/NetBSD-GNU-CXX.cmake b/Modules/Platform/NetBSD-GNU-CXX.cmake
new file mode 100644
index 0000000..55ad6b0
--- /dev/null
+++ b/Modules/Platform/NetBSD-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/NetBSD-GNU)
+__netbsd_compiler_gnu(CXX)
diff --git a/Modules/Platform/NetBSD-GNU-Fortran.cmake b/Modules/Platform/NetBSD-GNU-Fortran.cmake
new file mode 100644
index 0000000..eb85ecb
--- /dev/null
+++ b/Modules/Platform/NetBSD-GNU-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/NetBSD-GNU)
+__netbsd_compiler_gnu(Fortran)
diff --git a/Modules/Platform/NetBSD-GNU.cmake b/Modules/Platform/NetBSD-GNU.cmake
new file mode 100644
index 0000000..37abdeb
--- /dev/null
+++ b/Modules/Platform/NetBSD-GNU.cmake
@@ -0,0 +1,16 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file LICENSE.rst or https://cmake.org/licensing for details.
+
+include_guard()
+
+macro(__netbsd_compiler_gnu lang)
+  # linker selection
+  set(CMAKE_${lang}_USING_LINKER_SYSTEM "")
+  set(CMAKE_${lang}_USING_LINKER_LLD "-fuse-ld=lld")
+  set(CMAKE_${lang}_USING_LINKER_BFD "-fuse-ld=bfd")
+  set(CMAKE_${lang}_USING_LINKER_GOLD "-fuse-ld=gold")
+  if(NOT CMAKE_${lang}_COMPILER_ID STREQUAL "GNU"
+      OR CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
+    set(CMAKE_${lang}_USING_LINKER_MOLD "-fuse-ld=mold")
+  endif()
+endmacro()
diff --git a/Modules/Platform/OpenBSD-Clang-ASM.cmake b/Modules/Platform/OpenBSD-Clang-ASM.cmake
new file mode 100644
index 0000000..500eb68
--- /dev/null
+++ b/Modules/Platform/OpenBSD-Clang-ASM.cmake
@@ -0,0 +1 @@
+include(Platform/OpenBSD-GNU-ASM)
diff --git a/Modules/Platform/OpenBSD-Clang-C.cmake b/Modules/Platform/OpenBSD-Clang-C.cmake
new file mode 100644
index 0000000..86e511a
--- /dev/null
+++ b/Modules/Platform/OpenBSD-Clang-C.cmake
@@ -0,0 +1 @@
+include(Platform/OpenBSD-GNU-C)
diff --git a/Modules/Platform/OpenBSD-Clang-CXX.cmake b/Modules/Platform/OpenBSD-Clang-CXX.cmake
new file mode 100644
index 0000000..3faf012
--- /dev/null
+++ b/Modules/Platform/OpenBSD-Clang-CXX.cmake
@@ -0,0 +1 @@
+include(Platform/OpenBSD-GNU-CXX)
diff --git a/Modules/Platform/OpenBSD-GNU-ASM.cmake b/Modules/Platform/OpenBSD-GNU-ASM.cmake
new file mode 100644
index 0000000..f4eed41
--- /dev/null
+++ b/Modules/Platform/OpenBSD-GNU-ASM.cmake
@@ -0,0 +1,2 @@
+include(Platform/OpenBSD-GNU)
+__openbsd_compiler_gnu(ASM)
diff --git a/Modules/Platform/OpenBSD-GNU-C.cmake b/Modules/Platform/OpenBSD-GNU-C.cmake
new file mode 100644
index 0000000..ab94c4c
--- /dev/null
+++ b/Modules/Platform/OpenBSD-GNU-C.cmake
@@ -0,0 +1,2 @@
+include(Platform/OpenBSD-GNU)
+__openbsd_compiler_gnu(C)
diff --git a/Modules/Platform/OpenBSD-GNU-CXX.cmake b/Modules/Platform/OpenBSD-GNU-CXX.cmake
new file mode 100644
index 0000000..5829eb9
--- /dev/null
+++ b/Modules/Platform/OpenBSD-GNU-CXX.cmake
@@ -0,0 +1,2 @@
+include(Platform/OpenBSD-GNU)
+__openbsd_compiler_gnu(CXX)
diff --git a/Modules/Platform/OpenBSD-GNU-Fortran.cmake b/Modules/Platform/OpenBSD-GNU-Fortran.cmake
new file mode 100644
index 0000000..57fe66c
--- /dev/null
+++ b/Modules/Platform/OpenBSD-GNU-Fortran.cmake
@@ -0,0 +1,2 @@
+include(Platform/OpenBSD-GNU)
+__openbsd_compiler_gnu(Fortran)
diff --git a/Modules/Platform/OpenBSD-GNU.cmake b/Modules/Platform/OpenBSD-GNU.cmake
new file mode 100644
index 0000000..be4b1b4
--- /dev/null
+++ b/Modules/Platform/OpenBSD-GNU.cmake
@@ -0,0 +1,7 @@
+include_guard()
+
+include(Platform/NetBSD-GNU)
+
+macro(__openbsd_compiler_gnu lang)
+  __netbsd_compiler_gnu(${lang})
+endmacro()
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index 9ca8d6f..791db54 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -36,6 +36,8 @@
   set(CMAKE_${lang}_LINK_DEF_FILE_FLAG "-Xlinker /DEF:")
   set(CMAKE_LINK_DEF_FILE_FLAG "${CMAKE_${lang}_LINK_DEF_FILE_FLAG}")
 
+  set(CMAKE_${lang}_COMPILE_OPTIONS_SYSROOT "--sysroot=")
+
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ")
   set(CMAKE_${lang}_LINKER_WRAPPER_FLAG_SEP)
 
diff --git a/Modules/SquishTestScript.cmake b/Modules/SquishTestScript.cmake
index c4b45dc..9575084 100644
--- a/Modules/SquishTestScript.cmake
+++ b/Modules/SquishTestScript.cmake
@@ -4,7 +4,6 @@
 #[=======================================================================[.rst:
 SquishTestScript
 ----------------
-.. deprecated:: 3.0
 
 .. note::
 
diff --git a/Modules/TestBigEndian.cmake b/Modules/TestBigEndian.cmake
index a64303d..4b31780 100644
--- a/Modules/TestBigEndian.cmake
+++ b/Modules/TestBigEndian.cmake
@@ -7,19 +7,74 @@
 
 .. deprecated:: 3.20
 
-  Supserseded by the :variable:`CMAKE_<LANG>_BYTE_ORDER` variable.
+  Superseded by the :variable:`CMAKE_<LANG>_BYTE_ORDER` variable.
 
-Check if the target architecture is big endian or little endian.
+This module provides a command to check the endianness (byte order) of the
+target architecture.
+
+Load this module in a CMake project with:
+
+.. code-block:: cmake
+
+  include(TestBigEndian)
+
+Commands
+^^^^^^^^
+
+This module provides the following command:
 
 .. command:: test_big_endian
 
+  Checks if the target architecture is big-endian or little-endian:
+
   .. code-block:: cmake
 
     test_big_endian(<var>)
 
-  Stores in variable ``<var>`` either 1 or 0 indicating whether the
-  target architecture is big or little endian.
+  This command stores in variable ``<var>`` either 1 or 0 indicating whether
+  the target architecture is big or little endian.
 
+  At least one of the supported languages must be enabled in
+  CMake project when using this command.
+
+  Supported languages are ``C``, ``CXX``.
+
+  .. versionchanged:: 3.20
+    This command is now mainly a wrapper around the
+    :variable:`CMAKE_<LANG>_BYTE_ORDER` where also ``OBJC``, ``OBJCXX``,
+    and ``CUDA`` languages are supported.
+
+Examples
+^^^^^^^^
+
+Example: Checking Endianness
+""""""""""""""""""""""""""""
+
+Checking endianness of the target architecture with this module and storing
+the result in a CMake variable ``WORDS_BIGENDIAN``:
+
+.. code-block:: cmake
+
+  include(TestBigEndian)
+  test_big_endian(WORDS_BIGENDIAN)
+
+Example: Checking Endianness in New Code
+""""""""""""""""""""""""""""""""""""""""
+
+As of CMake 3.20, this module should be replaced with the
+:variable:`CMAKE_<LANG>_BYTE_ORDER` variable.  For example, in a project,
+where ``C`` language is one of the enabled languages:
+
+.. code-block:: cmake
+
+  if(CMAKE_C_BYTE_ORDER STREQUAL "BIG_ENDIAN")
+    set(WORDS_BIGENDIAN TRUE)
+  elseif(CMAKE_C_BYTE_ORDER STREQUAL "LITTLE_ENDIAN")
+    set(WORDS_BIGENDIAN FALSE)
+  else()
+    set(WORDS_BIGENDIAN FALSE)
+    message(WARNING "Endianness could not be determined.")
+  endif()
 #]=======================================================================]
 include_guard()
 
diff --git a/Modules/TestCXXAcceptsFlag.cmake b/Modules/TestCXXAcceptsFlag.cmake
index a39f8b3..69c7bc3 100644
--- a/Modules/TestCXXAcceptsFlag.cmake
+++ b/Modules/TestCXXAcceptsFlag.cmake
@@ -12,11 +12,19 @@
   :module:`CheckCompilerFlag` module is also available for checking flags across
   multiple languages.
 
-This module provides a macro to test whether the C++ (CXX) compiler supports
+This module provides a command to test whether the C++ (CXX) compiler supports
 specific flags.
 
-Macros
-^^^^^^
+Load this module in a CMake project with:
+
+.. code-block:: cmake
+
+  include(TestCXXAcceptsFlag)
+
+Commands
+^^^^^^^^
+
+This module provides the following command:
 
 .. command:: check_cxx_accepts_flag
 
diff --git a/Modules/UseJava/javaTargets.cmake.in b/Modules/UseJava/javaTargets.cmake.in
index 4aa6560..68643c4 100644
--- a/Modules/UseJava/javaTargets.cmake.in
+++ b/Modules/UseJava/javaTargets.cmake.in
@@ -1,5 +1,5 @@
 cmake_policy(PUSH)
-cmake_policy(VERSION 2.8.12...3.31)
+cmake_policy(VERSION 2.8.12...4.0)
 
 #----------------------------------------------------------------
 # Generated CMake Java target import file.
diff --git a/Modules/UsePkgConfig.cmake b/Modules/UsePkgConfig.cmake
index 2c34c26..b047013 100644
--- a/Modules/UsePkgConfig.cmake
+++ b/Modules/UsePkgConfig.cmake
@@ -10,7 +10,7 @@
   This module should no longer be used.  Instead, use the
   :module:`FindPkgConfig` module or the :command:`cmake_pkg_config` command.
 
-  This module provided a macro for finding external packages using
+  This module provided a command for finding external packages using
   ``pkg-config`` command-line utility.  It has been replaced by the more
   convenient ``FindPkgConfig`` module, which is commonly used in
   :ref:`Find Modules`.
@@ -18,10 +18,16 @@
   As of CMake 3.31, the built-in :command:`cmake_pkg_config` command provides
   even more features to extract package information.
 
-Macros
-^^^^^^
+Load this module in a CMake project with:
 
-This module defines the following macro:
+.. code-block:: cmake
+
+  include(UsePkgConfig)
+
+Commands
+^^^^^^^^
+
+This module provides the following command:
 
 .. command:: pkgconfig
 
@@ -31,9 +37,10 @@
 
     pkgconfig(<package> <includedir> <libdir> <linkflags> <cflags>)
 
-  This macro invokes ``pkg-config`` command-line utility to retrieve the package
-  information into specified variables.  If ``pkg-config`` or the specified
-  package ``<package>`` is NOT found, the result variables remain empty.
+  This command invokes ``pkg-config`` command-line utility to retrieve the
+  package information into specified variables.  If ``pkg-config`` or the
+  specified package ``<package>`` is NOT found, the result variables remain
+  empty.
 
   The arguments are:
 
diff --git a/Modules/Use_wxWindows.cmake b/Modules/Use_wxWindows.cmake
index e3c1870..aca80d9 100644
--- a/Modules/Use_wxWindows.cmake
+++ b/Modules/Use_wxWindows.cmake
@@ -7,28 +7,54 @@
 
 .. deprecated:: 2.8.10
 
-  Use :module:`find_package(wxWidgets) <FindwxWidgets>` instead.
+  This module should no longer be used.  Use :module:`find_package(wxWidgets)
+  <FindwxWidgets>` instead.
 
-This convenience include finds if wxWindows library is installed and sets the
-appropriate libraries, include directories, flags, etc.
+This module serves as a convenience wrapper for finding the wxWidgets library
+(formerly known as wxWindows) and propagates its usage requirements, such as
+libraries, include directories, and compiler flags, into the current directory
+scope for use by targets.
+
+Load this module in a CMake project with:
+
+.. code-block:: cmake
+
+  include(Use_wxWindows)
 
 Examples
 ^^^^^^^^
 
-Include ``Use_wxWindows`` module in project's ``CMakeLists.txt``:
+In earlier versions of CMake, wxWidgets (wxWindows) could be found and used in
+the current directory like this:
 
 .. code-block:: cmake
+  :caption: ``CMakeLists.txt``
 
-  # CMakeLists.txt
   include(Use_wxWindows)
 
-When the GL support is required, set ``WXWINDOWS_USE_GL`` *before* including
-this module:
+To request OpenGL support, the ``WXWINDOWS_USE_GL`` variable could be set before
+including this module:
 
 .. code-block:: cmake
+  :caption: ``CMakeLists.txt``
 
   set(WXWINDOWS_USE_GL ON)
   include(Use_wxWindows)
+
+  add_library(example example.cxx)
+
+Starting with CMake 3.0, wxWidgets can be found using the
+:module:`FindwxWidgets` module, which provides the wxWidgets usage requirements
+either using result variables or imported target as of CMake 3.27:
+
+.. code-block:: cmake
+  :caption: ``CMakeLists.txt``
+
+  find_package(wxWidgets)
+
+  add_library(example example.cxx)
+
+  target_link_libraries(example PRIVATE wxWidgets::wxWidgets)
 #]=======================================================================]
 
 # Author: Jan Woetzel <jw -at- mip.informatik.uni-kiel.de> (07/2003)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index b1c8290..a8f5fd1 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -148,8 +148,6 @@
   cmComputeTargetDepends.cxx
   cmConfigureLog.h
   cmConfigureLog.cxx
-  cmConstStack.h
-  cmConstStack.tcc
   cmCPackPropertiesGenerator.h
   cmCPackPropertiesGenerator.cxx
   cmCryptoHash.cxx
@@ -458,6 +456,8 @@
   cmSourceFileLocationKind.h
   cmSourceGroup.cxx
   cmSourceGroup.h
+  cmStack.h
+  cmStack.tcc
   cmStandardLevel.h
   cmStandardLevelResolver.cxx
   cmStandardLevelResolver.h
@@ -717,6 +717,9 @@
   cmSiteNameCommand.h
   cmSourceGroupCommand.cxx
   cmSourceGroupCommand.h
+  cmSPDXSerializer.cxx
+  cmSPDXSerializer.h
+  cmSPDXTypes.def
   cmString.cxx
   cmString.hxx
   cmStringReplaceHelper.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 9d20146..dba2090 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 4)
 set(CMake_VERSION_MINOR 1)
-set(CMake_VERSION_PATCH 0)
+set(CMake_VERSION_PATCH 20250814)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
index d5a9f0f..da6689a 100644
--- a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
@@ -15,6 +15,10 @@
 #include "cmUuid.h"
 #include "cmWIXAccessControlList.h"
 
+#ifdef _WIN32
+#  include "cmsys/Encoding.hxx"
+#endif
+
 cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(unsigned long wixVersion,
                                                cmCPackLog* logger,
                                                std::string const& filename,
@@ -144,7 +148,18 @@
   patch.ApplyFragment(componentId, *this);
   BeginElement("File");
   AddAttribute("Id", fileId);
-  AddAttribute("Source", CMakeToWixPath(filePath));
+
+  std::string sourcePath = CMakeToWixPath(filePath);
+#ifdef _WIN32
+  // WiX cannot handle long paths natively, but since v4,
+  // it supports long paths via UNC prefixes.
+  if (this->WixVersion >= 4) {
+    sourcePath = cmsys::Encoding::ToNarrow(
+      cmsys::Encoding::ToWindowsExtendedPath(sourcePath));
+  }
+#endif
+  AddAttribute("Source", sourcePath);
+
   AddAttribute("KeyPath", "yes");
 
   mode_t fileMode = 0;
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index d0d84db..1571bd1 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -312,7 +312,8 @@
 
 bool DebGenerator::generateControlTar(std::string const& md5Filename) const
 {
-  std::string filename_control_tar = this->WorkDir + "/control.tar.gz";
+  std::string filename_control_tar =
+    this->WorkDir + "/control.tar" + this->CompressionSuffix;
 
   cmGeneratedFileStream fileStream_control_tar;
   fileStream_control_tar.Open(filename_control_tar, false, true);
@@ -322,8 +323,7 @@
                     << filename_control_tar << "\" for writing" << std::endl);
     return false;
   }
-  cmArchiveWrite control_tar(fileStream_control_tar,
-                             cmArchiveWrite::CompressGZip,
+  cmArchiveWrite control_tar(fileStream_control_tar, this->TarCompressionType,
                              this->DebianArchiveType);
   if (!control_tar.Open()) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
@@ -484,7 +484,8 @@
   deb.SetUNAMEAndGNAME("root", "root");
 
   if (!deb.Add(tlDir + "debian-binary", tlDir.length()) ||
-      !deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
+      !deb.Add(tlDir + "control.tar" + this->CompressionSuffix,
+               tlDir.length()) ||
       !deb.Add(tlDir + "data.tar" + this->CompressionSuffix, tlDir.length())) {
     cmCPackLogger(cmCPackLog::LOG_ERROR,
                   "Error creating debian package:\n"
diff --git a/Source/CTest/cmCTestLaunch.cxx b/Source/CTest/cmCTestLaunch.cxx
index a929b39..286715f 100644
--- a/Source/CTest/cmCTestLaunch.cxx
+++ b/Source/CTest/cmCTestLaunch.cxx
@@ -14,6 +14,7 @@
 #include "cmsys/FStream.hxx"
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmCMakePath.h"
 #include "cmCTestLaunchReporter.h"
 #include "cmGlobalGenerator.h"
 #include "cmInstrumentation.h"
@@ -71,7 +72,8 @@
     DoingCurrentBuildDir,
     DoingCount,
     DoingFilterPrefix,
-    DoingConfig
+    DoingConfig,
+    DoingObjectDir
   };
   Doing doing = DoingNone;
   int arg0 = 0;
@@ -103,6 +105,8 @@
       doing = DoingFilterPrefix;
     } else if (strcmp(arg, "--config") == 0) {
       doing = DoingConfig;
+    } else if (strcmp(arg, "--object-dir") == 0) {
+      doing = DoingObjectDir;
     } else if (doing == DoingOutput) {
       this->Reporter.OptionOutput = arg;
       doing = DoingNone;
@@ -142,9 +146,28 @@
     } else if (doing == DoingConfig) {
       this->Reporter.OptionConfig = arg;
       doing = DoingNone;
+    } else if (doing == DoingObjectDir) {
+      this->Reporter.OptionObjectDir = arg;
+      doing = DoingNone;
     }
   }
 
+  // Older builds do not pass `--object-dir`, so construct a default if the
+  // components are available.
+  if (this->Reporter.OptionObjectDir.empty() &&
+      !this->Reporter.OptionCurrentBuildDir.empty() &&
+      !this->Reporter.OptionTargetName.empty()) {
+    this->Reporter.OptionObjectDir =
+      cmStrCat(this->Reporter.OptionCurrentBuildDir, "/CMakeFiles/",
+               this->Reporter.OptionTargetName, ".dir");
+  }
+  if (!this->Reporter.OptionObjectDir.empty() &&
+      !cmCMakePath(this->Reporter.OptionObjectDir).IsAbsolute() &&
+      !this->Reporter.OptionBuildDir.empty()) {
+    this->Reporter.OptionObjectDir = cmStrCat(
+      this->Reporter.OptionBuildDir, '/', this->Reporter.OptionObjectDir);
+  }
+
   // Extract the real command line.
   if (arg0) {
     for (int i = 0; i < argc - arg0; ++i) {
diff --git a/Source/CTest/cmCTestLaunchReporter.cxx b/Source/CTest/cmCTestLaunchReporter.cxx
index 2e1d2bb..a768e27 100644
--- a/Source/CTest/cmCTestLaunchReporter.cxx
+++ b/Source/CTest/cmCTestLaunchReporter.cxx
@@ -78,13 +78,12 @@
 
 void cmCTestLaunchReporter::LoadLabels()
 {
-  if (this->OptionCurrentBuildDir.empty() || this->OptionTargetName.empty()) {
+  if (this->OptionObjectDir.empty()) {
     return;
   }
 
   // Labels are listed in per-target files.
-  std::string fname = cmStrCat(this->OptionCurrentBuildDir, "/CMakeFiles/",
-                               this->OptionTargetName, ".dir/Labels.txt");
+  std::string fname = cmStrCat(this->OptionObjectDir, "/Labels.txt");
 
   // We are interested in per-target labels for this source file.
   std::string source = this->OptionSource;
diff --git a/Source/CTest/cmCTestLaunchReporter.h b/Source/CTest/cmCTestLaunchReporter.h
index cc32ced..59692e5 100644
--- a/Source/CTest/cmCTestLaunchReporter.h
+++ b/Source/CTest/cmCTestLaunchReporter.h
@@ -43,6 +43,7 @@
   std::string OptionCommandType;
   std::string OptionRole;
   std::string OptionConfig;
+  std::string OptionObjectDir;
 
   // The real command line appearing after launcher arguments.
   std::string CWD;
diff --git a/Source/CTest/cmCTestResourceAllocator.cxx b/Source/CTest/cmCTestResourceAllocator.cxx
index a7ae7bc..8aa2152 100644
--- a/Source/CTest/cmCTestResourceAllocator.cxx
+++ b/Source/CTest/cmCTestResourceAllocator.cxx
@@ -72,15 +72,3 @@
   resIt->second.Locked -= slots;
   return true;
 }
-
-bool cmCTestResourceAllocator::Resource::operator==(
-  Resource const& other) const
-{
-  return this->Total == other.Total && this->Locked == other.Locked;
-}
-
-bool cmCTestResourceAllocator::Resource::operator!=(
-  Resource const& other) const
-{
-  return !(*this == other);
-}
diff --git a/Source/CTest/cmCTestResourceAllocator.h b/Source/CTest/cmCTestResourceAllocator.h
index fcb5ef6..cf83c57 100644
--- a/Source/CTest/cmCTestResourceAllocator.h
+++ b/Source/CTest/cmCTestResourceAllocator.h
@@ -17,8 +17,15 @@
 
     unsigned int Free() const { return this->Total - this->Locked; }
 
-    bool operator==(Resource const& other) const;
-    bool operator!=(Resource const& other) const;
+    friend bool operator==(Resource left, Resource right)
+    {
+      return left.Total == right.Total && left.Locked == right.Locked;
+    }
+
+    friend bool operator!=(Resource left, Resource right)
+    {
+      return !(left == right);
+    }
   };
 
   void InitializeFromResourceSpec(cmCTestResourceSpec const& spec);
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 200ba03..49b71b6 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -9,8 +9,10 @@
 
 #include <cm/iomanip>
 #include <cm/optional>
+#include <cm/string>
 #include <cm/string_view>
 #include <cmext/algorithm>
+#include <cmext/string_view>
 
 #include <cm3p/curl/curl.h>
 #include <cm3p/json/reader.h>
@@ -226,6 +228,11 @@
       std::string remote_file =
         remoteprefix + cmSystemTools::GetFilenameName(file);
 
+      // Erase non-filename and non-space whitespace characters.
+      cm::erase_if(remote_file, [](char c) {
+        return cm::contains("\\:*?\"<>|\n\r\t\f\v"_s, c);
+      });
+
       *this->LogFile << "\tUpload file: " << local_file << " to "
                      << remote_file << std::endl;
 
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index a39cb7b..0c64f3f 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -530,7 +530,7 @@
 
 void cmCTestTestHandler::LogTestSummary(std::vector<std::string> const& passed,
                                         std::vector<std::string> const& failed,
-                                        cmDuration const& durationInSecs)
+                                        cmDuration durationInSecs)
 {
   std::size_t total = passed.size() + failed.size();
 
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 9388425..83aae98 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -242,7 +242,7 @@
   bool ProcessOptions();
   void LogTestSummary(std::vector<std::string> const& passed,
                       std::vector<std::string> const& failed,
-                      cmDuration const& durationInSecs);
+                      cmDuration durationInSecs);
   void LogDisabledTests(std::vector<cmCTestTestResult> const& disabledTests);
   void LogFailedTests(std::vector<std::string> const& failed,
                       SetOfTests const& resultsSet);
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index eefbbcf..70a1ebd 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -536,7 +536,7 @@
     case STATUS_NO_MEMORY:
     default:
       char buf[1024];
-      char const* fmt = "Exit code 0x%" KWIML_INT_PRIx64 "\n";
+      char const* fmt = "Exit code 0x%" KWIML_INT_PRIx64;
       snprintf(buf, sizeof(buf), fmt, this->ExitValue);
       exception_str.assign(buf);
   }
diff --git a/Source/Checks/Curses/CMakeLists.txt b/Source/Checks/Curses/CMakeLists.txt
index b074068..ed62602 100644
--- a/Source/Checks/Curses/CMakeLists.txt
+++ b/Source/Checks/Curses/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.13...3.31 FATAL_ERROR)
+cmake_minimum_required(VERSION 3.13...4.0 FATAL_ERROR)
 project(CheckCurses C)
 
 set(CURSES_NEED_NCURSES TRUE)
diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx
index 104436b..765e9cb 100644
--- a/Source/cmArgumentParser.cxx
+++ b/Source/cmArgumentParser.cxx
@@ -14,11 +14,9 @@
 auto KeywordActionMap::Emplace(cm::string_view name, KeywordAction action)
   -> std::pair<iterator, bool>
 {
-  auto const it =
-    std::lower_bound(this->begin(), this->end(), name,
-                     [](value_type const& elem, cm::string_view const& k) {
-                       return elem.first < k;
-                     });
+  auto const it = std::lower_bound(
+    this->begin(), this->end(), name,
+    [](value_type const& elem, cm::string_view k) { return elem.first < k; });
   return (it != this->end() && it->first == name)
     ? std::make_pair(it, false)
     : std::make_pair(this->emplace(it, name, std::move(action)), true);
@@ -26,11 +24,9 @@
 
 auto KeywordActionMap::Find(cm::string_view name) const -> const_iterator
 {
-  auto const it =
-    std::lower_bound(this->begin(), this->end(), name,
-                     [](value_type const& elem, cm::string_view const& k) {
-                       return elem.first < k;
-                     });
+  auto const it = std::lower_bound(
+    this->begin(), this->end(), name,
+    [](value_type const& elem, cm::string_view k) { return elem.first < k; });
   return (it != this->end() && it->first == name) ? it : this->end();
 }
 
@@ -56,8 +52,8 @@
 void Instance::Bind(std::function<Continue(cm::string_view)> f,
                     ExpectAtLeast expect)
 {
-  this->KeywordValueFunc = std::move(f);
-  this->KeywordValuesExpected = expect.Count;
+  this->GetState().KeywordValueFunc = std::move(f);
+  this->GetState().KeywordValuesExpected = expect.Count;
 }
 
 void Instance::Bind(bool& val)
@@ -81,7 +77,7 @@
   this->Bind(
     [this, &val](cm::string_view arg) -> Continue {
       if (arg.empty() && this->ParseResults) {
-        this->ParseResults->AddKeywordError(this->Keyword,
+        this->ParseResults->AddKeywordError(this->GetState().Keyword,
                                             "  empty string not allowed\n");
       }
       val = std::string(arg);
@@ -132,48 +128,50 @@
     ExpectAtLeast{ 0 });
 }
 
-void Instance::Consume(std::size_t pos, cm::string_view arg)
+void Instance::Consume(cm::string_view arg)
 {
-  auto const it = this->Bindings.Keywords.Find(arg);
-  if (it != this->Bindings.Keywords.end()) {
+  ParserState& state = this->GetState();
+
+  auto const it = state.Bindings.Keywords.Find(arg);
+  if (it != state.Bindings.Keywords.end()) {
     this->FinishKeyword();
-    this->Keyword = it->first;
-    this->KeywordValuesSeen = 0;
-    this->DoneWithPositional = true;
-    if (this->Bindings.ParsedKeyword) {
-      this->Bindings.ParsedKeyword(*this, it->first);
+    state.Keyword = it->first;
+    state.KeywordValuesSeen = 0;
+    state.DoneWithPositional = true;
+    if (state.Bindings.ParsedKeyword) {
+      state.Bindings.ParsedKeyword(*this, it->first);
     }
     it->second(*this);
     return;
   }
 
-  if (!this->DoneWithPositional) {
-    auto const pit = this->Bindings.Positions.Find(pos);
-    if (pit != this->Bindings.Positions.end()) {
-      pit->second(*this, pos, arg);
+  if (!state.DoneWithPositional) {
+    auto const pit = state.Bindings.Positions.Find(state.Pos);
+    if (pit != state.Bindings.Positions.end()) {
+      pit->second(*this, state.Pos, arg);
       return;
     }
 
-    if (this->Bindings.TrailingArgs) {
-      this->Keyword = ""_s;
-      this->KeywordValuesSeen = 0;
-      this->DoneWithPositional = true;
-      this->Bindings.TrailingArgs(*this);
-      if (!this->KeywordValueFunc) {
+    if (state.Bindings.TrailingArgs) {
+      state.Keyword = ""_s;
+      state.KeywordValuesSeen = 0;
+      state.DoneWithPositional = true;
+      state.Bindings.TrailingArgs(*this);
+      if (!state.KeywordValueFunc) {
         return;
       }
     }
   }
 
-  if (this->KeywordValueFunc) {
-    switch (this->KeywordValueFunc(arg)) {
+  if (state.KeywordValueFunc) {
+    switch (state.KeywordValueFunc(arg)) {
       case Continue::Yes:
         break;
       case Continue::No:
-        this->KeywordValueFunc = nullptr;
+        state.KeywordValueFunc = nullptr;
         break;
     }
-    ++this->KeywordValuesSeen;
+    ++state.KeywordValuesSeen;
     return;
   }
 
@@ -184,16 +182,18 @@
 
 void Instance::FinishKeyword()
 {
-  if (!this->DoneWithPositional) {
+  ParserState const& state = this->GetState();
+  if (!state.DoneWithPositional) {
     return;
   }
-  if (this->KeywordValuesSeen < this->KeywordValuesExpected) {
+
+  if (state.KeywordValuesSeen < state.KeywordValuesExpected) {
     if (this->ParseResults) {
-      this->ParseResults->AddKeywordError(this->Keyword,
+      this->ParseResults->AddKeywordError(state.Keyword,
                                           "  missing required value\n");
     }
-    if (this->Bindings.KeywordMissingValue) {
-      this->Bindings.KeywordMissingValue(*this, this->Keyword);
+    if (state.Bindings.KeywordMissingValue) {
+      state.Bindings.KeywordMissingValue(*this, state.Keyword);
     }
   }
 }
diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h
index 223c3ce..7893e2e 100644
--- a/Source/cmArgumentParser.h
+++ b/Source/cmArgumentParser.h
@@ -165,16 +165,49 @@
   }
 };
 
+class ParserState
+{
+public:
+  cm::string_view Keyword;
+  std::size_t Pos = 0;
+  std::size_t KeywordValuesSeen = 0;
+  std::size_t KeywordValuesExpected = 0;
+  std::function<Continue(cm::string_view)> KeywordValueFunc = nullptr;
+
+  ActionMap const& Bindings;
+  void* Result = nullptr;
+  bool DoneWithPositional = false;
+
+  ParserState(ActionMap const& bindings, void* result)
+    : Bindings(bindings)
+    , Result(result)
+  {
+  }
+};
+
 class Instance
 {
 public:
   Instance(ActionMap const& bindings, ParseResult* parseResult,
            std::vector<std::string>* unparsedArguments, void* result = nullptr)
-    : Bindings(bindings)
-    , ParseResults(parseResult)
+    : ParseResults(parseResult)
     , UnparsedArguments(unparsedArguments)
-    , Result(result)
   {
+    PushState(bindings, result);
+  }
+
+  ParserState& GetState() { return this->Stack.back(); }
+
+  void PushState(ActionMap const& bindings, void* result)
+  {
+    this->Stack.emplace_back(bindings, result);
+  }
+
+  void PopState()
+  {
+    if (!this->Stack.empty()) {
+      this->Stack.pop_back();
+    }
   }
 
   void Bind(std::function<Continue(cm::string_view)> f, ExpectAtLeast expect);
@@ -185,6 +218,7 @@
   void Bind(MaybeEmpty<std::vector<std::string>>& val);
   void Bind(NonEmpty<std::vector<std::string>>& val);
   void Bind(std::vector<std::vector<std::string>>& val);
+
   template <typename U>
   void Bind(NonEmpty<std::vector<std::pair<std::string, U>>>& val,
             U const& context)
@@ -217,27 +251,43 @@
   }
 
   template <typename Range>
-  void Parse(Range const& args, std::size_t pos = 0)
+  void Parse(Range& args, std::size_t const pos = 0)
   {
+    GetState().Pos = pos;
     for (cm::string_view arg : args) {
-      this->Consume(pos++, arg);
+      for (size_t j = 0; j < FindKeywordOwnerLevel(arg); ++j) {
+        this->PopState();
+      }
+
+      this->Consume(arg);
+      GetState().Pos++;
     }
+
     this->FinishKeyword();
+
+    while (this->Stack.size() > 1) {
+      this->FinishKeyword();
+      this->PopState();
+    }
+  }
+
+  std::size_t FindKeywordOwnerLevel(cm::string_view arg) const
+  {
+    for (std::size_t i = Stack.size(); i--;) {
+      if (this->Stack[i].Bindings.Keywords.Find(arg) !=
+          this->Stack[i].Bindings.Keywords.end()) {
+        return (this->Stack.size() - 1) - i;
+      }
+    }
+    return 0;
   }
 
 private:
-  ActionMap const& Bindings;
+  std::vector<ParserState> Stack;
   ParseResult* ParseResults = nullptr;
   std::vector<std::string>* UnparsedArguments = nullptr;
-  void* Result = nullptr;
 
-  cm::string_view Keyword;
-  std::size_t KeywordValuesSeen = 0;
-  std::size_t KeywordValuesExpected = 0;
-  std::function<Continue(cm::string_view)> KeywordValueFunc;
-  bool DoneWithPositional = false;
-
-  void Consume(std::size_t pos, cm::string_view arg);
+  void Consume(cm::string_view arg);
   void FinishKeyword();
 
   template <typename Result>
@@ -250,6 +300,8 @@
 class cmArgumentParser : private ArgumentParser::Base
 {
 public:
+  using Base::Bindings;
+
   // I *think* this function could be made `constexpr` when the code is
   // compiled as C++20.  This would allow building a parser at compile time.
   template <typename T, typename cT = cm::member_pointer_class_t<T>,
@@ -259,7 +311,7 @@
   cmArgumentParser& Bind(cm::static_string_view name, T member)
   {
     this->Base::Bind(name, [member](Instance& instance) {
-      instance.Bind(static_cast<Result*>(instance.Result)->*member);
+      instance.Bind(static_cast<Result*>(instance.GetState().Result)->*member);
     });
     return *this;
   }
@@ -269,7 +321,7 @@
                                     T Result::*member, U Result::*context)
   {
     this->Base::Bind(name, [member, context](Instance& instance) {
-      auto* result = static_cast<Result*>(instance.Result);
+      auto* result = static_cast<Result*>(instance.GetState().Result);
       instance.Bind(result->*member, result->*context);
     });
     return *this;
@@ -280,7 +332,7 @@
                          ExpectAtLeast expect = { 1 })
   {
     this->Base::Bind(name, [member, expect](Instance& instance) {
-      Result* result = static_cast<Result*>(instance.Result);
+      Result* result = static_cast<Result*>(instance.GetState().Result);
       instance.Bind(
         [result, member](cm::string_view arg) -> Continue {
           return (result->*member)(arg);
@@ -296,8 +348,8 @@
                          ExpectAtLeast expect = { 1 })
   {
     this->Base::Bind(name, [member, expect](Instance& instance) {
-      Result* result = static_cast<Result*>(instance.Result);
-      cm::string_view keyword = instance.Keyword;
+      Result* result = static_cast<Result*>(instance.GetState().Result);
+      cm::string_view keyword = instance.GetState().Keyword;
       instance.Bind(
         [result, member, keyword](cm::string_view arg) -> Continue {
           return (result->*member)(keyword, arg);
@@ -312,7 +364,7 @@
                          ExpectAtLeast expect = { 1 })
   {
     this->Base::Bind(name, [f, expect](Instance& instance) {
-      Result* result = static_cast<Result*>(instance.Result);
+      Result* result = static_cast<Result*>(instance.GetState().Result);
       instance.Bind(
         [result, &f](cm::string_view arg) -> Continue {
           return f(*result, arg);
@@ -328,8 +380,8 @@
     ExpectAtLeast expect = { 1 })
   {
     this->Base::Bind(name, [f, expect](Instance& instance) {
-      Result* result = static_cast<Result*>(instance.Result);
-      cm::string_view keyword = instance.Keyword;
+      Result* result = static_cast<Result*>(instance.GetState().Result);
+      cm::string_view keyword = instance.GetState().Keyword;
       instance.Bind(
         [result, keyword, &f](cm::string_view arg) -> Continue {
           return f(*result, keyword, arg);
@@ -345,7 +397,7 @@
     this->Base::Bind(
       position,
       [member](Instance& instance, std::size_t, cm::string_view arg) {
-        Result* result = static_cast<Result*>(instance.Result);
+        Result* result = static_cast<Result*>(instance.GetState().Result);
         result->*member = arg;
       });
     return *this;
@@ -356,7 +408,8 @@
   {
     this->Base::BindParsedKeyword(
       [member](Instance& instance, cm::string_view arg) {
-        (static_cast<Result*>(instance.Result)->*member).emplace_back(arg);
+        (static_cast<Result*>(instance.GetState().Result)->*member)
+          .emplace_back(arg);
       });
     return *this;
   }
@@ -368,11 +421,44 @@
   cmArgumentParser& BindTrailingArgs(T member)
   {
     this->Base::BindTrailingArgs([member](Instance& instance) {
-      instance.Bind(static_cast<Result*>(instance.Result)->*member);
+      instance.Bind(static_cast<Result*>(instance.GetState().Result)->*member);
     });
     return *this;
   }
 
+  template <typename T, typename U>
+  cmArgumentParser& BindSubParser(cm::static_string_view name,
+                                  cmArgumentParser<T>& parser,
+                                  cm::optional<T> U::*member)
+  {
+
+    this->Base::Bind(name, [name, parser, member](Instance& instance) {
+      auto* parentResult = static_cast<Result*>(instance.GetState().Result);
+      auto& childResult = parentResult->*member;
+      childResult.emplace(T());
+      instance.Bind(nullptr, ExpectAtLeast{ 0 });
+      instance.PushState(parser.Bindings, &(*childResult));
+      instance.Consume(name);
+    });
+
+    return *this;
+  }
+
+  template <typename T, typename U>
+  cmArgumentParser& BindSubParser(cm::static_string_view name,
+                                  cmArgumentParser<T>& parser, T U::*member)
+  {
+    this->Base::Bind(name, [name, parser, member](Instance& instance) {
+      auto* parentResult = static_cast<Result*>(instance.GetState().Result);
+      auto* childResult = &(parentResult->*member);
+      instance.Bind(nullptr, ExpectAtLeast{ 1 });
+      instance.PushState(parser.Bindings, childResult);
+      instance.Consume(name);
+    });
+
+    return *this;
+  }
+
   template <typename Range>
   bool Parse(Result& result, Range const& args,
              std::vector<std::string>* unparsedArguments,
@@ -405,6 +491,8 @@
 class cmArgumentParser<void> : private ArgumentParser::Base
 {
 public:
+  using Base::Bindings;
+
   template <typename T>
   cmArgumentParser& Bind(cm::static_string_view name, T& ref)
   {
@@ -429,7 +517,7 @@
     ExpectAtLeast expect = { 1 })
   {
     this->Base::Bind(name, [f, expect](Instance& instance) {
-      cm::string_view keyword = instance.Keyword;
+      cm::string_view keyword = instance.GetState().Keyword;
       instance.Bind(
         [keyword, &f](cm::string_view arg) -> Continue {
           return f(keyword, arg);
@@ -463,6 +551,32 @@
     return *this;
   }
 
+  template <typename T, typename U>
+  cmArgumentParser& BindSubParser(cm::static_string_view name,
+                                  cmArgumentParser<T>& parser,
+                                  cm::optional<U>& subResult)
+  {
+    this->Base::Bind(name, [name, parser, &subResult](Instance& instance) {
+      subResult.emplace(U());
+      instance.Bind(nullptr, ExpectAtLeast{ 0 });
+      instance.PushState(parser.Bindings, &(*subResult));
+      instance.Consume(name);
+    });
+    return *this;
+  }
+
+  template <typename T, typename U>
+  cmArgumentParser& BindSubParser(cm::static_string_view name,
+                                  cmArgumentParser<T>& parser, U& subResult)
+  {
+    this->Base::Bind(name, [name, parser, &subResult](Instance& instance) {
+      instance.Bind(nullptr, ExpectAtLeast{ 1 });
+      instance.PushState(parser.Bindings, &subResult);
+      instance.Consume(name);
+    });
+    return *this;
+  }
+
   template <typename Range>
   ParseResult Parse(Range const& args,
                     std::vector<std::string>* unparsedArguments,
diff --git a/Source/cmBuildOptions.h b/Source/cmBuildOptions.h
index f84b576..a10b69f 100644
--- a/Source/cmBuildOptions.h
+++ b/Source/cmBuildOptions.h
@@ -35,8 +35,6 @@
     , ResolveMode(resolveMode)
   {
   }
-  explicit cmBuildOptions(cmBuildOptions const&) noexcept = default;
-  cmBuildOptions& operator=(cmBuildOptions const&) noexcept = default;
 
   bool Clean = false;
   bool Fast = false;
diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx
index 00b59c6..51b7c30 100644
--- a/Source/cmCMakeHostSystemInformationCommand.cxx
+++ b/Source/cmCMakeHostSystemInformationCommand.cxx
@@ -303,7 +303,7 @@
     scripts = gl.GetFiles();
   }
 
-  // 2. User provided (append to the CMake prvided)
+  // 2. User provided (append to the CMake provided)
   cmList::append(
     scripts, makefile.GetDefinition("CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS"));
 
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index f6c0536..48741ac 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -114,7 +114,6 @@
   bool UseHTTP10 = false;
   bool PrintLabels = false;
   bool Failover = false;
-  bool UseVerboseInstrumentation = false;
   cmJSONState parseState;
 
   bool FlushTestProgressLine = false;
@@ -320,10 +319,6 @@
     this->Impl->TestProgressOutput = !cmIsOff(envValue);
   }
   envValue.clear();
-  if (cmSystemTools::GetEnv("CTEST_USE_VERBOSE_INSTRUMENTATION", envValue)) {
-    this->Impl->UseVerboseInstrumentation = !cmIsOff(envValue);
-  }
-  envValue.clear();
 
   this->Impl->Parts[PartStart].SetName("Start");
   this->Impl->Parts[PartUpdate].SetName("Update");
@@ -1005,32 +1000,7 @@
 
 std::string cmCTest::SafeBuildIdField(std::string const& value)
 {
-  std::string safevalue(value);
-
-  if (!safevalue.empty()) {
-    // Disallow non-filename and non-space whitespace characters.
-    // If they occur, replace them with ""
-    //
-    char const* disallowed = "\\:*?\"<>|\n\r\t\f\v";
-
-    if (safevalue.find_first_of(disallowed) != std::string::npos) {
-      std::string::size_type i = 0;
-      std::string::size_type n = strlen(disallowed);
-      char replace[2];
-      replace[1] = 0;
-
-      for (i = 0; i < n; ++i) {
-        replace[0] = disallowed[i];
-        cmSystemTools::ReplaceString(safevalue, replace, "");
-      }
-    }
-  }
-
-  if (safevalue.empty()) {
-    safevalue = "(empty)";
-  }
-
-  return safevalue;
+  return value.empty() ? "(empty)" : value;
 }
 
 void cmCTest::StartXML(cmXMLWriter& xml, cmake* cm, bool append)
@@ -3654,11 +3624,6 @@
   return *this->Impl->Instrumentation;
 }
 
-bool cmCTest::GetUseVerboseInstrumentation() const
-{
-  return this->Impl->UseVerboseInstrumentation;
-}
-
 void cmCTest::ConvertInstrumentationSnippetsToXML(cmXMLWriter& xml,
                                                   std::string const& subdir)
 {
@@ -3687,6 +3652,8 @@
 bool cmCTest::ConvertInstrumentationJSONFileToXML(std::string const& fpath,
                                                   cmXMLWriter& xml)
 {
+  bool verboseCommands = this->GetInstrumentation().HasOption(
+    cmInstrumentationQuery::Option::CDashVerbose);
   Json::Value root;
   this->Impl->parseState = cmJSONState(fpath, &root);
   if (!this->Impl->parseState.errors.empty()) {
@@ -3735,7 +3702,7 @@
       }
       // Truncate the full command line if verbose instrumentation
       // was not requested.
-      if (key == "command" && !this->GetUseVerboseInstrumentation()) {
+      if (key == "command" && !verboseCommands) {
         std::string command_str = root[key].asString();
         std::string truncated = command_str.substr(0, command_str.find(' '));
         if (command_str != truncated) {
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 6dfa0bc..46c88b7 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -436,7 +436,6 @@
   std::vector<std::string> GetCommandLineHttpHeaders() const;
 
   cmInstrumentation& GetInstrumentation();
-  bool GetUseVerboseInstrumentation() const;
 
 private:
   int GenerateNotesFile(cmake* cm, std::string const& files);
diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx
index ed23958..1d3f933 100644
--- a/Source/cmComputeLinkDepends.cxx
+++ b/Source/cmComputeLinkDepends.cxx
@@ -779,7 +779,7 @@
 }
 
 std::pair<size_t, bool> cmComputeLinkDepends::AddLinkEntry(
-  cmLinkItem const& item, cm::optional<size_t> const& groupIndex)
+  cmLinkItem const& item, cm::optional<size_t> groupIndex)
 {
   // Allocate a spot for the item entry.
   auto lei = this->AllocateLinkEntry(item);
@@ -950,7 +950,7 @@
 }
 
 void cmComputeLinkDepends::AddVarLinkEntries(
-  cm::optional<size_t> const& depender_index, char const* value)
+  cm::optional<size_t> depender_index, char const* value)
 {
   // This is called to add the dependencies named by
   // <item>_LIB_DEPENDS.  The variable contains a semicolon-separated
@@ -1020,8 +1020,8 @@
 }
 
 template <typename T>
-void cmComputeLinkDepends::AddLinkEntries(
-  cm::optional<size_t> const& depender_index, std::vector<T> const& libs)
+void cmComputeLinkDepends::AddLinkEntries(cm::optional<size_t> depender_index,
+                                          std::vector<T> const& libs)
 {
   // Track inferred dependency sets implied by this list.
   std::map<size_t, DependSet> dependSets;
@@ -1305,7 +1305,7 @@
 }
 
 cmLinkItem cmComputeLinkDepends::ResolveLinkItem(
-  cm::optional<size_t> const& depender_index, std::string const& name)
+  cm::optional<size_t> depender_index, std::string const& name)
 {
   // Look for a target in the scope of the depender.
   cmGeneratorTarget const* from = this->Target;
diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h
index a82db2b..0724561 100644
--- a/Source/cmComputeLinkDepends.h
+++ b/Source/cmComputeLinkDepends.h
@@ -106,16 +106,16 @@
   std::pair<std::map<cmLinkItem, size_t>::iterator, bool> AllocateLinkEntry(
     cmLinkItem const& item);
   std::pair<size_t, bool> AddLinkEntry(cmLinkItem const& item,
-                                       cm::optional<size_t> const& groupIndex);
+                                       cm::optional<size_t> groupIndex);
   void AddLinkObject(cmLinkItem const& item);
-  void AddVarLinkEntries(cm::optional<size_t> const& depender_index,
+  void AddVarLinkEntries(cm::optional<size_t> depender_index,
                          char const* value);
   void AddDirectLinkEntries();
   template <typename T>
-  void AddLinkEntries(cm::optional<size_t> const& depender_index,
+  void AddLinkEntries(cm::optional<size_t> depender_index,
                       std::vector<T> const& libs);
   void AddLinkObjects(std::vector<cmLinkItem> const& objs);
-  cmLinkItem ResolveLinkItem(cm::optional<size_t> const& depender_index,
+  cmLinkItem ResolveLinkItem(cm::optional<size_t> depender_index,
                              std::string const& name);
 
   // One entry for each unique item.
diff --git a/Source/cmConfigureLog.cxx b/Source/cmConfigureLog.cxx
index b486cc3..5f0c3c6 100644
--- a/Source/cmConfigureLog.cxx
+++ b/Source/cmConfigureLog.cxx
@@ -23,12 +23,12 @@
 #include "cmake.h"
 
 cmConfigureLog::cmConfigureLog(std::string logDir,
-                               std::vector<unsigned long> logVersions)
+                               std::vector<unsigned int> logVersions)
   : LogDir(std::move(logDir))
   , LogVersions(std::move(logVersions))
 {
   // Always emit events for the latest log version.
-  static unsigned long const LatestLogVersion = 1;
+  static unsigned int const LatestLogVersion = 1;
   if (!cm::contains(this->LogVersions, LatestLogVersion)) {
     this->LogVersions.emplace_back(LatestLogVersion);
   }
@@ -46,7 +46,7 @@
 }
 
 bool cmConfigureLog::IsAnyLogVersionEnabled(
-  std::vector<unsigned long> const& v) const
+  std::vector<unsigned int> const& v) const
 {
   // Both input lists are sorted.  Look for a matching element.
   auto i1 = v.cbegin();
diff --git a/Source/cmConfigureLog.h b/Source/cmConfigureLog.h
index 6c6c44f..a485041 100644
--- a/Source/cmConfigureLog.h
+++ b/Source/cmConfigureLog.h
@@ -22,12 +22,12 @@
 public:
   /** Construct with the log directory and a sorted list of enabled log
       versions.  The latest log version will be enabled regardless.  */
-  cmConfigureLog(std::string logDir, std::vector<unsigned long> logVersions);
+  cmConfigureLog(std::string logDir, std::vector<unsigned int> logVersions);
   ~cmConfigureLog();
 
   /** Return true if at least one of the log versions in the given sorted
       list is enabled.  */
-  bool IsAnyLogVersionEnabled(std::vector<unsigned long> const& v) const;
+  bool IsAnyLogVersionEnabled(std::vector<unsigned int> const& v) const;
 
   void EnsureInit();
 
@@ -60,7 +60,7 @@
 
 private:
   std::string LogDir;
-  std::vector<unsigned long> LogVersions;
+  std::vector<unsigned int> LogVersions;
   cmsys::ofstream Stream;
   unsigned Indent = 0;
   bool Opened = false;
diff --git a/Source/cmConstStack.h b/Source/cmConstStack.h
deleted file mode 100644
index d6059e7..0000000
--- a/Source/cmConstStack.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file LICENSE.rst or https://cmake.org/licensing for details.  */
-#pragma once
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <memory>
-
-/** Base class template for CRTP to represent a stack of constant values.
-    Provide value semantics, but use efficient reference-counting underneath
-    to avoid copies.  */
-template <typename T, typename Stack>
-class cmConstStack
-{
-  struct Entry;
-  std::shared_ptr<Entry const> TopEntry;
-
-public:
-  /** Default-construct an empty stack.  */
-  cmConstStack();
-
-  /** Get a stack with the given call context added to the top.  */
-  Stack Push(T value) const;
-
-  /** Get a stack with the top level removed.
-      May not be called until after a matching Push.  */
-  Stack Pop() const;
-
-  /** Get the value at the top of the stack.
-      This may be called only if Empty() would return false.  */
-  T const& Top() const;
-
-  /** Return true if this stack is empty.  */
-  bool Empty() const;
-
-protected:
-  cmConstStack(std::shared_ptr<Entry const> parent, T value);
-  cmConstStack(std::shared_ptr<Entry const> top);
-};
diff --git a/Source/cmConstStack.tcc b/Source/cmConstStack.tcc
deleted file mode 100644
index ee69c9c..0000000
--- a/Source/cmConstStack.tcc
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file LICENSE.rst or https://cmake.org/licensing for details.  */
-
-#include <cassert>
-#include <memory>
-#include <utility>
-
-template <typename T, typename Stack>
-struct cmConstStack<T, Stack>::Entry
-{
-  Entry(std::shared_ptr<Entry const> parent, T value)
-    : Value(std::move(value))
-    , Parent(std::move(parent))
-  {
-  }
-
-  T Value;
-  std::shared_ptr<Entry const> Parent;
-};
-
-template <typename T, typename Stack>
-cmConstStack<T, Stack>::cmConstStack() = default;
-
-template <typename T, typename Stack>
-Stack cmConstStack<T, Stack>::Push(T value) const
-{
-  return Stack(this->TopEntry, std::move(value));
-}
-
-template <typename T, typename Stack>
-Stack cmConstStack<T, Stack>::Pop() const
-{
-  assert(this->TopEntry);
-  return Stack(this->TopEntry->Parent);
-}
-
-template <typename T, typename Stack>
-T const& cmConstStack<T, Stack>::Top() const
-{
-  assert(this->TopEntry);
-  return this->TopEntry->Value;
-}
-
-template <typename T, typename Stack>
-bool cmConstStack<T, Stack>::Empty() const
-{
-  return !this->TopEntry;
-}
-
-template <typename T, typename Stack>
-cmConstStack<T, Stack>::cmConstStack(std::shared_ptr<Entry const> parent,
-                                     T value)
-  : TopEntry(
-      std::make_shared<Entry const>(std::move(parent), std::move(value)))
-{
-}
-
-template <typename T, typename Stack>
-cmConstStack<T, Stack>::cmConstStack(std::shared_ptr<Entry const> top)
-  : TopEntry(std::move(top))
-{
-}
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index eb8f616..721f29f 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -236,7 +236,7 @@
 }
 
 Arguments cmCoreTryCompile::ParseArgs(
-  cmRange<std::vector<std::string>::const_iterator> const& args,
+  cmRange<std::vector<std::string>::const_iterator> args,
   cmArgumentParser<Arguments> const& parser,
   std::vector<std::string>& unparsedArguments)
 {
@@ -1386,6 +1386,14 @@
     return;
   }
 
+  if (cmHasLiteralSuffix(outputFileLocation, ".js")) {
+    std::string wasmOutputLocation = cmStrCat(
+      outputFileLocation.substr(0, outputFileLocation.length() - 3), ".wasm");
+    if (cmSystemTools::FileExists(wasmOutputLocation)) {
+      outputFileLocation = wasmOutputLocation;
+    }
+  }
+
   this->OutputFile = cmSystemTools::CollapseFullPath(outputFileLocation);
 }
 
diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h
index 41d712f..3c36456 100644
--- a/Source/cmCoreTryCompile.h
+++ b/Source/cmCoreTryCompile.h
@@ -161,8 +161,7 @@
   std::string WriteSource(std::string const& name, std::string const& content,
                           char const* command) const;
 
-  Arguments ParseArgs(
-    cmRange<std::vector<std::string>::const_iterator> const& args,
-    cmArgumentParser<Arguments> const& parser,
-    std::vector<std::string>& unparsedArguments);
+  Arguments ParseArgs(cmRange<std::vector<std::string>::const_iterator> args,
+                      cmArgumentParser<Arguments> const& parser,
+                      std::vector<std::string>& unparsedArguments);
 };
diff --git a/Source/cmDebuggerAdapter.cxx b/Source/cmDebuggerAdapter.cxx
index 7dc6e7f..7cf9efe 100644
--- a/Source/cmDebuggerAdapter.cxx
+++ b/Source/cmDebuggerAdapter.cxx
@@ -164,8 +164,7 @@
     });
 
   // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Threads
-  Session->registerHandler([this](dap::ThreadsRequest const& req) {
-    (void)req;
+  Session->registerHandler([this](dap::ThreadsRequest /*unused*/) {
     std::unique_lock<std::mutex> lock(Mutex);
     dap::ThreadsResponse response;
 
@@ -196,7 +195,7 @@
   });
 
   // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Scopes
-  Session->registerHandler([this](dap::ScopesRequest const& request)
+  Session->registerHandler([this](dap::ScopesRequest request)
                              -> dap::ResponseOrError<dap::ScopesResponse> {
     std::unique_lock<std::mutex> lock(Mutex);
     return DefaultThread->GetScopesResponse(request.frameId,
@@ -210,8 +209,7 @@
   });
 
   // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Pause
-  Session->registerHandler([this](dap::PauseRequest const& req) {
-    (void)req;
+  Session->registerHandler([this](dap::PauseRequest /*unused*/) {
     PauseRequest.store(true);
     return dap::PauseResponse();
   });
@@ -286,8 +284,7 @@
   // The ConfigurationDone request is made by the client once all configuration
   // requests have been made.
   // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_ConfigurationDone
-  Session->registerHandler([this](dap::ConfigurationDoneRequest const& req) {
-    (void)req;
+  Session->registerHandler([this](dap::ConfigurationDoneRequest /*unused*/) {
     ConfigurationDoneEvent->Fire();
     return dap::ConfigurationDoneResponse();
   });
@@ -397,7 +394,7 @@
     dap::array<dap::integer> hitBreakpoints;
     hitBreakpoints.resize(hits.size());
     std::transform(hits.begin(), hits.end(), hitBreakpoints.begin(),
-                   [&](int64_t const& id) { return dap::integer(id); });
+                   [&](int64_t id) { return dap::integer(id); });
     stoppedEvent.reason = "breakpoint";
     stoppedEvent.hitBreakpointIds = hitBreakpoints;
   }
diff --git a/Source/cmDebuggerBreakpointManager.cxx b/Source/cmDebuggerBreakpointManager.cxx
index dfd131c..b33985b 100644
--- a/Source/cmDebuggerBreakpointManager.cxx
+++ b/Source/cmDebuggerBreakpointManager.cxx
@@ -33,7 +33,7 @@
   auto location =
     find_if(ListFileFunctionLines[sourcePath].begin(),
             ListFileFunctionLines[sourcePath].end(),
-            [=](cmDebuggerFunctionLocation const& loc) {
+            [=](cmDebuggerFunctionLocation loc) {
               return loc.StartLine <= line && loc.EndLine >= line;
             });
 
@@ -47,11 +47,10 @@
 int64_t cmDebuggerBreakpointManager::CalibrateBreakpointLine(
   std::string const& sourcePath, int64_t line)
 {
-  auto location = find_if(ListFileFunctionLines[sourcePath].begin(),
-                          ListFileFunctionLines[sourcePath].end(),
-                          [=](cmDebuggerFunctionLocation const& loc) {
-                            return loc.StartLine >= line;
-                          });
+  auto location = find_if(
+    ListFileFunctionLines[sourcePath].begin(),
+    ListFileFunctionLines[sourcePath].end(),
+    [=](cmDebuggerFunctionLocation loc) { return loc.StartLine >= line; });
 
   if (location != ListFileFunctionLines[sourcePath].end()) {
     return location->StartLine;
diff --git a/Source/cmDebuggerExceptionManager.cxx b/Source/cmDebuggerExceptionManager.cxx
index a2744e1..22a577a 100644
--- a/Source/cmDebuggerExceptionManager.cxx
+++ b/Source/cmDebuggerExceptionManager.cxx
@@ -25,8 +25,7 @@
     });
 
   // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_ExceptionInfo
-  DapSession->registerHandler([&](dap::ExceptionInfoRequest const& request) {
-    (void)request;
+  DapSession->registerHandler([&](dap::ExceptionInfoRequest /*unused*/) {
     return HandleExceptionInfoRequest();
   });
 
diff --git a/Source/cmDebuggerVariablesHelper.cxx b/Source/cmDebuggerVariablesHelper.cxx
index b8bc328..efe5c89 100644
--- a/Source/cmDebuggerVariablesHelper.cxx
+++ b/Source/cmDebuggerVariablesHelper.cxx
@@ -83,8 +83,7 @@
 
 std::shared_ptr<cmDebuggerVariables> cmDebuggerVariablesHelper::CreateIfAny(
   std::shared_ptr<cmDebuggerVariablesManager> const& variablesManager,
-  std::string const& name, bool supportsVariableType,
-  cmBTStringRange const& entries)
+  std::string const& name, bool supportsVariableType, cmBTStringRange entries)
 {
   if (entries.empty()) {
     return {};
diff --git a/Source/cmDebuggerVariablesHelper.h b/Source/cmDebuggerVariablesHelper.h
index e39a857..0e0fdb4 100644
--- a/Source/cmDebuggerVariablesHelper.h
+++ b/Source/cmDebuggerVariablesHelper.h
@@ -48,7 +48,7 @@
   static std::shared_ptr<cmDebuggerVariables> CreateIfAny(
     std::shared_ptr<cmDebuggerVariablesManager> const& variablesManager,
     std::string const& name, bool supportsVariableType,
-    cmBTStringRange const& entries);
+    cmBTStringRange entries);
 
   static std::shared_ptr<cmDebuggerVariables> CreateIfAny(
     std::shared_ptr<cmDebuggerVariablesManager> const& variablesManager,
diff --git a/Source/cmDuration.cxx b/Source/cmDuration.cxx
index b017d0a..7981e77 100644
--- a/Source/cmDuration.cxx
+++ b/Source/cmDuration.cxx
@@ -4,7 +4,7 @@
 #include "cmDuration.h"
 
 template <typename T>
-T cmDurationTo(cmDuration const& duration)
+T cmDurationTo(cmDuration duration)
 {
   /* This works because the comparison operators for duration rely on
    * std::common_type.
@@ -23,5 +23,5 @@
     .count();
 }
 
-template int cmDurationTo<int>(cmDuration const&);
-template unsigned int cmDurationTo<unsigned int>(cmDuration const&);
+template int cmDurationTo<int>(cmDuration);
+template unsigned int cmDurationTo<unsigned int>(cmDuration);
diff --git a/Source/cmDuration.h b/Source/cmDuration.h
index c0268f9..378af9c 100644
--- a/Source/cmDuration.h
+++ b/Source/cmDuration.h
@@ -16,9 +16,9 @@
  * the permissible valid values for T.
  */
 template <typename T>
-T cmDurationTo(cmDuration const& duration);
+T cmDurationTo(cmDuration duration);
 
 #ifndef CMDURATION_CPP
-extern template int cmDurationTo<int>(cmDuration const&);
-extern template unsigned int cmDurationTo<unsigned int>(cmDuration const&);
+extern template int cmDurationTo<int>(cmDuration);
+extern template unsigned int cmDurationTo<unsigned int>(cmDuration);
 #endif
diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx
index 2a018bc..167b99c 100644
--- a/Source/cmExperimental.cxx
+++ b/Source/cmExperimental.cxx
@@ -65,7 +65,7 @@
     cmExperimental::TryCompileCondition::Never },
   // Instrumentation
   { "Instrumentation",
-    "a37d1069-1972-4901-b9c9-f194aaf2b6e0",
+    "d16a3082-c4e1-489b-b90c-55750a334f27",
     "CMAKE_EXPERIMENTAL_INSTRUMENTATION",
     "CMake's support for collecting instrumentation data is experimental. It "
     "is meant only for experimentation and feedback to CMake developers.",
diff --git a/Source/cmExportBuildPackageInfoGenerator.cxx b/Source/cmExportBuildPackageInfoGenerator.cxx
index 980bb29..c1677a8 100644
--- a/Source/cmExportBuildPackageInfoGenerator.cxx
+++ b/Source/cmExportBuildPackageInfoGenerator.cxx
@@ -3,6 +3,7 @@
 #include "cmExportBuildPackageInfoGenerator.h"
 
 #include <cassert>
+#include <map>
 #include <utility>
 #include <vector>
 
@@ -10,7 +11,9 @@
 
 #include <cm3p/json/value.h>
 
+#include "cmAlgorithms.h"
 #include "cmGeneratorExpression.h"
+#include "cmList.h"
 #include "cmPackageInfoArguments.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -68,6 +71,14 @@
       }
     }
 
+    // De-duplicate include directories prior to generation.
+    auto it = properties.find("INTERFACE_INCLUDE_DIRECTORIES");
+    if (it != properties.end()) {
+      auto list = cmList{ it->second };
+      list = cmList{ list.begin(), cmRemoveDuplicates(list) };
+      properties["INTERFACE_INCLUDE_DIRECTORIES"] = list.to_string();
+    }
+
     // Set configuration-agnostic properties for component.
     this->GenerateInterfaceProperties(*component, target, properties);
   }
diff --git a/Source/cmExportCMakeConfigGenerator.cxx b/Source/cmExportCMakeConfigGenerator.cxx
index ce9610a..27eb31b 100644
--- a/Source/cmExportCMakeConfigGenerator.cxx
+++ b/Source/cmExportCMakeConfigGenerator.cxx
@@ -173,7 +173,7 @@
   // Isolate the file policy level.
   // Support CMake versions as far back as the
   // RequiredCMakeVersion{Major,Minor,Patch}, but also support using NEW
-  // policy settings for up to CMake 3.31 (this upper limit may be reviewed
+  // policy settings for up to CMake 4.0 (this upper limit may be reviewed
   // and increased from time to time). This reduces the opportunity for CMake
   // warnings when an older export file is later used with newer CMake
   // versions.
@@ -182,7 +182,7 @@
         "cmake_policy(VERSION "
      << this->RequiredCMakeVersionMajor << '.'
      << this->RequiredCMakeVersionMinor << '.'
-     << this->RequiredCMakeVersionPatch << "...3.31)\n";
+     << this->RequiredCMakeVersionPatch << "...4.0)\n";
   /* clang-format on */
 }
 
@@ -451,16 +451,27 @@
       return lhs.second.FindPackageIndex < rhs.second.FindPackageIndex;
     });
 
+  // Unwinding is only valid in a find_package() context
+  os << "if(DEFINED CMAKE_FIND_PACKAGE_NAME)\n"
+     << "  set(_cmake_unwind_arg UNWIND_INCLUDE)\n"
+     << "endif()\n\n";
+
   for (auto const& it : packageDependenciesSorted) {
     if (it.second.Enabled == cmExportSet::PackageDependencyExportEnabled::On) {
-      os << "find_dependency(" << it.first;
+      os << "__find_dependency_no_return(" << it.first;
       for (auto const& arg : it.second.ExtraArguments) {
         os << ' ' << cmOutputConverter::EscapeForCMake(arg);
       }
-      os << ")\n";
+      os << " ${_cmake_unwind_arg})\n";
+      os << "if(NOT " << it.first << "_FOUND)\n"
+         << "  unset(_cmake_unwind_arg)\n"
+         << "  cmake_policy(POP)\n"
+         << "  return()\n"
+         << "endif()\n\n";
     }
   }
-  os << "\n\n";
+
+  os << "unset(_cmake_unwind_arg)\n\n\n";
 }
 
 void cmExportCMakeConfigGenerator::GenerateMissingTargetsCheckCode(
diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx
index 42590f3..fdd6418 100644
--- a/Source/cmExportCommand.cxx
+++ b/Source/cmExportCommand.cxx
@@ -32,6 +32,7 @@
 #include "cmRange.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
+#include "cmSubcommandTable.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
 #include "cmValue.h"
@@ -45,73 +46,33 @@
 #  include <windows.h>
 #endif
 
-static bool HandlePackage(std::vector<std::string> const& args,
-                          cmExecutionStatus& status);
-
 static void StorePackageRegistry(cmMakefile& mf, std::string const& package,
                                  char const* content, char const* hash);
 
-bool cmExportCommand(std::vector<std::string> const& args,
-                     cmExecutionStatus& status)
+static bool HandleTargetsMode(std::vector<std::string> const& args,
+                              cmExecutionStatus& status)
 {
-  if (args.size() < 2) {
-    status.SetError("called with too few arguments");
-    return false;
-  }
-
-  if (args[0] == "PACKAGE") {
-    return HandlePackage(args, status);
-  }
-
-  struct Arguments : cmPackageInfoArguments
+  struct Arguments
   {
     cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Targets;
     ArgumentParser::NonEmpty<std::string> ExportSetName;
     ArgumentParser::NonEmpty<std::string> Namespace;
     ArgumentParser::NonEmpty<std::string> Filename;
-    ArgumentParser::NonEmpty<std::string> AndroidMKFile;
     ArgumentParser::NonEmpty<std::string> CxxModulesDirectory;
+    ArgumentParser::NonEmpty<std::string> AndroidMKFile;
+
     bool Append = false;
     bool ExportOld = false;
-
-    std::vector<std::vector<std::string>> PackageDependencyArgs;
-    bool ExportPackageDependencies = false;
-
-    std::vector<std::vector<std::string>> TargetArgs;
   };
 
   auto parser =
     cmArgumentParser<Arguments>{}
       .Bind("NAMESPACE"_s, &Arguments::Namespace)
       .Bind("FILE"_s, &Arguments::Filename)
-      .Bind("CXX_MODULES_DIRECTORY"_s, &Arguments::CxxModulesDirectory);
-
-  if (args[0] == "EXPORT") {
-    parser.Bind("EXPORT"_s, &Arguments::ExportSetName);
-    if (cmExperimental::HasSupportEnabled(
-          status.GetMakefile(),
-          cmExperimental::Feature::ExportPackageDependencies)) {
-      parser.Bind("EXPORT_PACKAGE_DEPENDENCIES"_s,
-                  &Arguments::ExportPackageDependencies);
-    }
-    if (cmExperimental::HasSupportEnabled(
-          status.GetMakefile(), cmExperimental::Feature::ExportPackageInfo)) {
-      cmPackageInfoArguments::Bind(parser);
-    }
-  } else if (args[0] == "SETUP") {
-    parser.Bind("SETUP"_s, &Arguments::ExportSetName);
-    if (cmExperimental::HasSupportEnabled(
-          status.GetMakefile(),
-          cmExperimental::Feature::ExportPackageDependencies)) {
-      parser.Bind("PACKAGE_DEPENDENCY"_s, &Arguments::PackageDependencyArgs);
-    }
-    parser.Bind("TARGET"_s, &Arguments::TargetArgs);
-  } else {
-    parser.Bind("TARGETS"_s, &Arguments::Targets);
-    parser.Bind("ANDROID_MK"_s, &Arguments::AndroidMKFile);
-    parser.Bind("APPEND"_s, &Arguments::Append);
-    parser.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, &Arguments::ExportOld);
-  }
+      .Bind("CXX_MODULES_DIRECTORY"_s, &Arguments::CxxModulesDirectory)
+      .Bind("TARGETS"_s, &Arguments::Targets)
+      .Bind("APPEND"_s, &Arguments::Append)
+      .Bind("ANDROID_MK"_s, &Arguments::AndroidMKFile);
 
   std::vector<std::string> unknownArgs;
   Arguments arguments = parser.Parse(args, &unknownArgs);
@@ -121,127 +82,13 @@
     return false;
   }
 
-  if (args[0] == "SETUP") {
-    cmMakefile& mf = status.GetMakefile();
-    cmGlobalGenerator* gg = mf.GetGlobalGenerator();
-
-    cmExportSetMap& setMap = gg->GetExportSets();
-    auto& exportSet = setMap[arguments.ExportSetName];
-
-    struct PackageDependencyArguments
-    {
-      std::string Enabled;
-      ArgumentParser::MaybeEmpty<std::vector<std::string>> ExtraArgs;
-    };
-
-    auto packageDependencyParser =
-      cmArgumentParser<PackageDependencyArguments>{}
-        .Bind("ENABLED"_s, &PackageDependencyArguments::Enabled)
-        .Bind("EXTRA_ARGS"_s, &PackageDependencyArguments::ExtraArgs);
-
-    for (auto const& packageDependencyArgs : arguments.PackageDependencyArgs) {
-      if (packageDependencyArgs.empty()) {
-        continue;
-      }
-
-      PackageDependencyArguments const packageDependencyArguments =
-        packageDependencyParser.Parse(
-          cmMakeRange(packageDependencyArgs).advance(1), &unknownArgs);
-
-      if (!unknownArgs.empty()) {
-        status.SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
-        return false;
-      }
-
-      auto& packageDependency =
-        exportSet.GetPackageDependencyForSetup(packageDependencyArgs.front());
-
-      if (!packageDependencyArguments.Enabled.empty()) {
-        if (packageDependencyArguments.Enabled == "AUTO") {
-          packageDependency.Enabled =
-            cmExportSet::PackageDependencyExportEnabled::Auto;
-        } else if (cmIsOff(packageDependencyArguments.Enabled)) {
-          packageDependency.Enabled =
-            cmExportSet::PackageDependencyExportEnabled::Off;
-        } else if (cmIsOn(packageDependencyArguments.Enabled)) {
-          packageDependency.Enabled =
-            cmExportSet::PackageDependencyExportEnabled::On;
-        } else {
-          status.SetError(
-            cmStrCat("Invalid enable setting for package dependency: \"",
-                     packageDependencyArguments.Enabled, '"'));
-          return false;
-        }
-      }
-
-      cm::append(packageDependency.ExtraArguments,
-                 packageDependencyArguments.ExtraArgs);
-    }
-
-    struct TargetArguments
-    {
-      std::string XcFrameworkLocation;
-    };
-
-    auto targetParser = cmArgumentParser<TargetArguments>{}.Bind(
-      "XCFRAMEWORK_LOCATION"_s, &TargetArguments::XcFrameworkLocation);
-
-    for (auto const& targetArgs : arguments.TargetArgs) {
-      if (targetArgs.empty()) {
-        continue;
-      }
-
-      TargetArguments const targetArguments =
-        targetParser.Parse(cmMakeRange(targetArgs).advance(1), &unknownArgs);
-
-      if (!unknownArgs.empty()) {
-        status.SetError("Unknown argument: \"" + unknownArgs.front() + "\".");
-        return false;
-      }
-
-      exportSet.SetXcFrameworkLocation(targetArgs.front(),
-                                       targetArguments.XcFrameworkLocation);
-    }
-
-    return true;
-  }
-
-  if (arguments.PackageName.empty()) {
-    if (!arguments.Check(status, false)) {
-      return false;
-    }
-  } else {
-    if (!arguments.Filename.empty()) {
-      status.SetError("PACKAGE_INFO and FILE are mutually exclusive.");
-      return false;
-    }
-    if (!arguments.Namespace.empty()) {
-      status.SetError("PACKAGE_INFO and NAMESPACE are mutually exclusive.");
-      return false;
-    }
-    if (!arguments.Check(status) ||
-        !arguments.SetMetadataFromProject(status)) {
-      return false;
-    }
-  }
-
   std::string fname;
   bool android = false;
-  bool cps = false;
   if (!arguments.AndroidMKFile.empty()) {
     fname = arguments.AndroidMKFile;
     android = true;
   } else if (arguments.Filename.empty()) {
-    if (args[0] != "EXPORT") {
-      status.SetError("FILE <filename> option missing.");
-      return false;
-    }
-    if (arguments.PackageName.empty()) {
-      fname = arguments.ExportSetName + ".cmake";
-    } else {
-      fname = arguments.GetPackageFileName();
-      cps = true;
-    }
+    fname = arguments.ExportSetName + ".cmake";
   } else {
     // Make sure the file has a .cmake extension.
     if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) !=
@@ -273,66 +120,43 @@
   }
 
   std::vector<cmExportBuildFileGenerator::TargetExport> targets;
-
   cmGlobalGenerator* gg = mf.GetGlobalGenerator();
 
-  cmExportSet* exportSet = nullptr;
-  if (args[0] == "EXPORT") {
-    cmExportSetMap& setMap = gg->GetExportSets();
-    auto const it = setMap.find(arguments.ExportSetName);
-    if (it == setMap.end()) {
+  for (std::string const& currentTarget : *arguments.Targets) {
+    if (mf.IsAlias(currentTarget)) {
       std::ostringstream e;
-      e << "Export set \"" << arguments.ExportSetName << "\" not found.";
+      e << "given ALIAS target \"" << currentTarget
+        << "\" which may not be exported.";
       status.SetError(e.str());
       return false;
     }
-    exportSet = &it->second;
-  } else if (arguments.Targets) {
-    for (std::string const& currentTarget : *arguments.Targets) {
-      if (mf.IsAlias(currentTarget)) {
-        std::ostringstream e;
-        e << "given ALIAS target \"" << currentTarget
-          << "\" which may not be exported.";
-        status.SetError(e.str());
-        return false;
-      }
 
-      if (cmTarget* target = gg->FindTarget(currentTarget)) {
-        if (target->GetType() == cmStateEnums::UTILITY) {
-          status.SetError("given custom target \"" + currentTarget +
-                          "\" which may not be exported.");
-          return false;
-        }
-      } else {
-        std::ostringstream e;
-        e << "given target \"" << currentTarget
-          << "\" which is not built by this project.";
-        status.SetError(e.str());
+    if (cmTarget* target = gg->FindTarget(currentTarget)) {
+      if (target->GetType() == cmStateEnums::UTILITY) {
+        status.SetError("given custom target \"" + currentTarget +
+                        "\" which may not be exported.");
         return false;
       }
-      targets.emplace_back(currentTarget, std::string{});
+    } else {
+      std::ostringstream e;
+      e << "given target \"" << currentTarget
+        << "\" which is not built by this project.";
+      status.SetError(e.str());
+      return false;
     }
-    if (arguments.Append) {
-      if (cmExportBuildFileGenerator* ebfg =
-            gg->GetExportedTargetsFile(fname)) {
-        ebfg->AppendTargets(targets);
-        return true;
-      }
+    targets.emplace_back(currentTarget, std::string{});
+  }
+  if (arguments.Append) {
+    if (cmExportBuildFileGenerator* ebfg = gg->GetExportedTargetsFile(fname)) {
+      ebfg->AppendTargets(targets);
+      return true;
     }
-  } else {
-    status.SetError("EXPORT or TARGETS specifier missing.");
-    return false;
   }
 
   // if cmExportBuildFileGenerator is already defined for the file
   // and APPEND is not specified, if CMP0103 is OLD ignore previous definition
   // else raise an error
   if (gg->GetExportedTargetsFile(fname)) {
-    if (cps) {
-      status.SetError(cmStrCat("command already specified for the file "_s,
-                               cmSystemTools::GetFilenameName(fname), '.'));
-      return false;
-    }
     switch (mf.GetPolicyStatus(cmPolicies::CMP0103)) {
       case cmPolicies::WARN:
         mf.IssueMessage(
@@ -352,33 +176,174 @@
     }
   }
 
-  // Set up export file generation.
   std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr;
   if (android) {
     auto ebag = cm::make_unique<cmExportBuildAndroidMKGenerator>();
     ebag->SetNamespace(arguments.Namespace);
     ebag->SetAppendMode(arguments.Append);
     ebfg = std::move(ebag);
-  } else if (cps) {
-    auto ebpg = cm::make_unique<cmExportBuildPackageInfoGenerator>(arguments);
-    ebfg = std::move(ebpg);
   } else {
     auto ebcg = cm::make_unique<cmExportBuildCMakeConfigGenerator>();
     ebcg->SetNamespace(arguments.Namespace);
     ebcg->SetAppendMode(arguments.Append);
     ebcg->SetExportOld(arguments.ExportOld);
+    ebfg = std::move(ebcg);
+  }
+
+  ebfg->SetExportFile(fname.c_str());
+  ebfg->SetCxxModuleDirectory(arguments.CxxModulesDirectory);
+  ebfg->SetTargets(targets);
+  std::vector<std::string> configurationTypes =
+    mf.GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+
+  for (std::string const& ct : configurationTypes) {
+    ebfg->AddConfiguration(ct);
+  }
+  gg->AddBuildExportSet(ebfg.get());
+  mf.AddExportBuildFileGenerator(std::move(ebfg));
+
+  return true;
+}
+
+static bool HandleExportMode(std::vector<std::string> const& args,
+                             cmExecutionStatus& status)
+{
+  struct ExportArguments
+  {
+    ArgumentParser::NonEmpty<std::string> ExportSetName;
+    ArgumentParser::NonEmpty<std::string> Namespace;
+    ArgumentParser::NonEmpty<std::string> Filename;
+    ArgumentParser::NonEmpty<std::string> CxxModulesDirectory;
+    cm::optional<cmPackageInfoArguments> PackageInfo;
+    bool ExportPackageDependencies = false;
+  };
+
+  auto parser =
+    cmArgumentParser<ExportArguments>{}
+      .Bind("EXPORT"_s, &ExportArguments::ExportSetName)
+      .Bind("NAMESPACE"_s, &ExportArguments::Namespace)
+      .Bind("FILE"_s, &ExportArguments::Filename)
+      .Bind("CXX_MODULES_DIRECTORY"_s, &ExportArguments::CxxModulesDirectory);
+
+  if (cmExperimental::HasSupportEnabled(
+        status.GetMakefile(),
+        cmExperimental::Feature::ExportPackageDependencies)) {
+    parser.Bind("EXPORT_PACKAGE_DEPENDENCIES"_s,
+                &ExportArguments::ExportPackageDependencies);
+  }
+
+  cmArgumentParser<cmPackageInfoArguments> packageInfoParser;
+  cmPackageInfoArguments::Bind(packageInfoParser);
+
+  if (cmExperimental::HasSupportEnabled(
+        status.GetMakefile(), cmExperimental::Feature::ExportPackageInfo)) {
+    parser.BindSubParser("PACKAGE_INFO"_s, packageInfoParser,
+                         &ExportArguments::PackageInfo);
+  }
+
+  std::vector<std::string> unknownArgs;
+  ExportArguments arguments = parser.Parse(args, &unknownArgs);
+
+  cmMakefile& mf = status.GetMakefile();
+  cmGlobalGenerator* gg = mf.GetGlobalGenerator();
+
+  if (arguments.PackageInfo) {
+    if (arguments.PackageInfo->PackageName.empty()) {
+      if (!arguments.PackageInfo->Check(status, false)) {
+        return false;
+      }
+    } else {
+      if (!arguments.Filename.empty()) {
+        status.SetError("PACKAGE_INFO and FILE are mutually exclusive.");
+        return false;
+      }
+      if (!arguments.Namespace.empty()) {
+        status.SetError("PACKAGE_INFO and NAMESPACE are mutually exclusive.");
+        return false;
+      }
+      if (!arguments.PackageInfo->Check(status) ||
+          !arguments.PackageInfo->SetMetadataFromProject(status)) {
+        return false;
+      }
+    }
+  }
+
+  if (!unknownArgs.empty()) {
+    status.SetError("EXPORT subcommand given unknown argument: \"" +
+                    unknownArgs.front() + "\".");
+    return false;
+  }
+
+  std::string fname;
+  if (arguments.Filename.empty()) {
+    if (arguments.PackageInfo) {
+      fname = arguments.PackageInfo->GetPackageFileName();
+    } else {
+      fname = arguments.ExportSetName + ".cmake";
+    }
+  } else {
+    if (cmSystemTools::GetFilenameLastExtension(arguments.Filename) !=
+        ".cmake") {
+      std::ostringstream e;
+      e << "FILE option given filename \"" << arguments.Filename
+        << "\" which does not have an extension of \".cmake\".\n";
+      status.SetError(e.str());
+      return false;
+    }
+    fname = arguments.Filename;
+  }
+
+  if (cmSystemTools::FileIsFullPath(fname)) {
+    if (!mf.CanIWriteThisFile(fname)) {
+      std::ostringstream e;
+      e << "FILE option given filename \"" << fname
+        << "\" which is in the source tree.\n";
+      status.SetError(e.str());
+      return false;
+    }
+  } else {
+    // Interpret relative paths with respect to the current build dir.
+    std::string const& dir = mf.GetCurrentBinaryDirectory();
+    fname = dir + "/" + fname;
+  }
+
+  if (gg->GetExportedTargetsFile(fname)) {
+    if (arguments.PackageInfo) {
+      status.SetError(cmStrCat("command already specified for the file "_s,
+                               cmSystemTools::GetFilenameName(fname), '.'));
+      return false;
+    }
+  }
+
+  cmExportSet* exportSet = nullptr;
+  cmExportSetMap& setMap = gg->GetExportSets();
+  auto const it = setMap.find(arguments.ExportSetName);
+  if (it == setMap.end()) {
+    std::ostringstream e;
+    e << "Export set \"" << arguments.ExportSetName << "\" not found.";
+    status.SetError(e.str());
+    return false;
+  }
+  exportSet = &it->second;
+
+  // Set up export file generation.
+  std::unique_ptr<cmExportBuildFileGenerator> ebfg = nullptr;
+  if (arguments.PackageInfo) {
+    auto ebpg = cm::make_unique<cmExportBuildPackageInfoGenerator>(
+      *arguments.PackageInfo);
+    ebfg = std::move(ebpg);
+  } else {
+    auto ebcg = cm::make_unique<cmExportBuildCMakeConfigGenerator>();
+    ebcg->SetNamespace(arguments.Namespace);
     ebcg->SetExportPackageDependencies(arguments.ExportPackageDependencies);
     ebfg = std::move(ebcg);
   }
+
   ebfg->SetExportFile(fname.c_str());
   ebfg->SetCxxModuleDirectory(arguments.CxxModulesDirectory);
   if (exportSet) {
     ebfg->SetExportSet(exportSet);
-  } else {
-    ebfg->SetTargets(targets);
   }
-
-  // Compute the set of configurations exported.
   std::vector<std::string> configurationTypes =
     mf.GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
 
@@ -387,16 +352,123 @@
   }
   if (exportSet) {
     gg->AddBuildExportExportSet(ebfg.get());
-  } else {
-    gg->AddBuildExportSet(ebfg.get());
   }
-  mf.AddExportBuildFileGenerator(std::move(ebfg));
 
+  mf.AddExportBuildFileGenerator(std::move(ebfg));
   return true;
 }
 
-static bool HandlePackage(std::vector<std::string> const& args,
-                          cmExecutionStatus& status)
+static bool HandleSetupMode(std::vector<std::string> const& args,
+                            cmExecutionStatus& status)
+{
+  struct SetupArguments
+  {
+    ArgumentParser::NonEmpty<std::string> ExportSetName;
+    ArgumentParser::NonEmpty<std::string> CxxModulesDirectory;
+    std::vector<std::vector<std::string>> PackageDependencyArgs;
+    std::vector<std::vector<std::string>> TargetArgs;
+  };
+
+  auto parser = cmArgumentParser<SetupArguments>{};
+  parser.Bind("SETUP"_s, &SetupArguments::ExportSetName);
+  if (cmExperimental::HasSupportEnabled(
+        status.GetMakefile(),
+        cmExperimental::Feature::ExportPackageDependencies)) {
+    parser.Bind("PACKAGE_DEPENDENCY"_s,
+                &SetupArguments::PackageDependencyArgs);
+  }
+  parser.Bind("TARGET"_s, &SetupArguments::TargetArgs);
+
+  std::vector<std::string> unknownArgs;
+  SetupArguments arguments = parser.Parse(args, &unknownArgs);
+
+  if (!unknownArgs.empty()) {
+    status.SetError("SETUP subcommand given unknown argument: \"" +
+                    unknownArgs.front() + "\".");
+    return false;
+  }
+
+  cmMakefile& mf = status.GetMakefile();
+  cmGlobalGenerator* gg = mf.GetGlobalGenerator();
+
+  cmExportSetMap& setMap = gg->GetExportSets();
+  auto& exportSet = setMap[arguments.ExportSetName];
+
+  struct PackageDependencyArguments
+  {
+    std::string Enabled;
+    ArgumentParser::MaybeEmpty<std::vector<std::string>> ExtraArgs;
+  };
+
+  auto packageDependencyParser =
+    cmArgumentParser<PackageDependencyArguments>{}
+      .Bind("ENABLED"_s, &PackageDependencyArguments::Enabled)
+      .Bind("EXTRA_ARGS"_s, &PackageDependencyArguments::ExtraArgs);
+
+  for (auto const& packageDependencyArgs : arguments.PackageDependencyArgs) {
+    if (packageDependencyArgs.empty()) {
+      continue;
+    }
+    PackageDependencyArguments const packageDependencyArguments =
+      packageDependencyParser.Parse(
+        cmMakeRange(packageDependencyArgs).advance(1), &unknownArgs);
+
+    if (!unknownArgs.empty()) {
+      status.SetError("PACKAGE_DEPENDENCY given unknown argument: \"" +
+                      unknownArgs.front() + "\".");
+      return false;
+    }
+    auto& packageDependency =
+      exportSet.GetPackageDependencyForSetup(packageDependencyArgs.front());
+    if (!packageDependencyArguments.Enabled.empty()) {
+      if (packageDependencyArguments.Enabled == "AUTO") {
+        packageDependency.Enabled =
+          cmExportSet::PackageDependencyExportEnabled::Auto;
+      } else if (cmIsOff(packageDependencyArguments.Enabled)) {
+        packageDependency.Enabled =
+          cmExportSet::PackageDependencyExportEnabled::Off;
+      } else if (cmIsOn(packageDependencyArguments.Enabled)) {
+        packageDependency.Enabled =
+          cmExportSet::PackageDependencyExportEnabled::On;
+      } else {
+        status.SetError(
+          cmStrCat("Invalid enable setting for package dependency: \"",
+                   packageDependencyArguments.Enabled, '"'));
+        return false;
+      }
+    }
+    cm::append(packageDependency.ExtraArguments,
+               packageDependencyArguments.ExtraArgs);
+  }
+
+  struct TargetArguments
+  {
+    std::string XcFrameworkLocation;
+  };
+
+  auto targetParser = cmArgumentParser<TargetArguments>{}.Bind(
+    "XCFRAMEWORK_LOCATION"_s, &TargetArguments::XcFrameworkLocation);
+
+  for (auto const& targetArgs : arguments.TargetArgs) {
+    if (targetArgs.empty()) {
+      continue;
+    }
+    TargetArguments const targetArguments =
+      targetParser.Parse(cmMakeRange(targetArgs).advance(1), &unknownArgs);
+
+    if (!unknownArgs.empty()) {
+      status.SetError("TARGET given unknown argument: \"" +
+                      unknownArgs.front() + "\".");
+      return false;
+    }
+    exportSet.SetXcFrameworkLocation(targetArgs.front(),
+                                     targetArguments.XcFrameworkLocation);
+  }
+  return true;
+}
+
+static bool HandlePackageMode(std::vector<std::string> const& args,
+                              cmExecutionStatus& status)
 {
   // Parse PACKAGE mode arguments.
   enum Doing
@@ -545,3 +617,20 @@
   }
 }
 #endif
+
+bool cmExportCommand(std::vector<std::string> const& args,
+                     cmExecutionStatus& status)
+{
+  if (args.empty()) {
+    return true;
+  }
+
+  static cmSubcommandTable const subcommand{
+    { "TARGETS"_s, HandleTargetsMode },
+    { "EXPORT"_s, HandleExportMode },
+    { "SETUP"_s, HandleSetupMode },
+    { "PACKAGE"_s, HandlePackageMode },
+  };
+
+  return subcommand(args[0], args, status);
+}
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 477453d..fdf0dbd 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -215,7 +215,7 @@
   cmGeneratorExpression::Split(exportDirs, entries);
   exportDirs.clear();
   char const* sep = "";
-  cm::string_view const& prefixWithSlash = this->GetImportPrefixWithSlash();
+  cm::string_view const prefixWithSlash = this->GetImportPrefixWithSlash();
   for (std::string const& e : entries) {
     exportDirs += sep;
     sep = ";";
diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h
index 2df3264..85da195 100644
--- a/Source/cmExportInstallFileGenerator.h
+++ b/Source/cmExportInstallFileGenerator.h
@@ -75,7 +75,7 @@
 
   std::string GetInstallPrefix() const
   {
-    cm::string_view const& prefixWithSlash = this->GetImportPrefixWithSlash();
+    cm::string_view const prefixWithSlash = this->GetImportPrefixWithSlash();
     return std::string(prefixWithSlash.data(), prefixWithSlash.length() - 1);
   }
   virtual char GetConfigFileNameSeparator() const = 0;
diff --git a/Source/cmExportInstallPackageInfoGenerator.cxx b/Source/cmExportInstallPackageInfoGenerator.cxx
index 5a660c4..0fa8bef 100644
--- a/Source/cmExportInstallPackageInfoGenerator.cxx
+++ b/Source/cmExportInstallPackageInfoGenerator.cxx
@@ -2,19 +2,32 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmExportInstallPackageInfoGenerator.h"
 
+#include <map>
 #include <memory>
 #include <set>
+#include <sstream>
 #include <utility>
 #include <vector>
 
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/algorithm>
+#include <cmext/string_view>
+
 #include <cm3p/json/value.h>
 
+#include "cmAlgorithms.h"
 #include "cmExportSet.h"
+#include "cmFileSet.h"
 #include "cmGeneratorExpression.h"
 #include "cmGeneratorTarget.h"
 #include "cmInstallExportGenerator.h"
+#include "cmInstallFileSetGenerator.h"
+#include "cmList.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
+#include "cmMessageType.h"
+#include "cmOutputConverter.h"
 #include "cmPackageInfoArguments.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
@@ -67,7 +80,6 @@
   root["cps_path"] = packagePath;
 
   // Create all the imported targets.
-  bool requiresConfigFiles = false;
   for (cmTargetExport const* te : allTargets) {
     cmGeneratorTarget* gt = te->Target;
     cmStateEnums::TargetType targetType = this->GetExportTargetType(te);
@@ -86,11 +98,22 @@
       gt, cmGeneratorExpression::InstallInterface, properties);
 
     if (targetType != cmStateEnums::INTERFACE_LIBRARY) {
-      requiresConfigFiles = true;
+      this->RequiresConfigFiles = true;
+    }
+
+    // De-duplicate include directories prior to generation.
+    auto it = properties.find("INTERFACE_INCLUDE_DIRECTORIES");
+    if (it != properties.end()) {
+      auto list = cmList{ it->second };
+      list = cmList{ list.begin(), cmRemoveDuplicates(list) };
+      properties["INTERFACE_INCLUDE_DIRECTORIES"] = list.to_string();
     }
 
     // Set configuration-agnostic properties for component.
     this->GenerateInterfaceProperties(*component, gt, properties);
+    if (!this->GenerateFileSetProperties(*component, gt, te)) {
+      return false;
+    }
   }
 
   this->GeneratePackageRequires(root);
@@ -101,7 +124,7 @@
   bool result = true;
 
   // Generate an import file for each configuration.
-  if (requiresConfigFiles) {
+  if (this->RequiresConfigFiles) {
     for (std::string const& c : this->Configurations) {
       if (!this->GenerateImportFileConfig(c)) {
         result = false;
@@ -123,19 +146,19 @@
 
   for (auto const& te : this->GetExportSet()->GetTargetExports()) {
     // Collect import properties for this target.
-    if (this->GetExportTargetType(te.get()) ==
-        cmStateEnums::INTERFACE_LIBRARY) {
-      continue;
-    }
-
     ImportPropertyMap properties;
     std::set<std::string> importedLocations;
 
-    this->PopulateImportProperties(config, suffix, te.get(), properties,
-                                   importedLocations);
+    if (this->GetExportTargetType(te.get()) !=
+        cmStateEnums::INTERFACE_LIBRARY) {
+      this->PopulateImportProperties(config, suffix, te.get(), properties,
+                                     importedLocations);
+    }
 
     Json::Value component =
       this->GenerateInterfaceConfigProperties(suffix, properties);
+    this->GenerateFileSetProperties(component, te->Target, te.get(), config);
+
     if (!component.empty()) {
       components[te->Target->GetExportName()] = std::move(component);
     }
@@ -193,3 +216,82 @@
   // return IEGen->GetCxxModuleDirectory();
   return {};
 }
+
+cm::optional<std::string>
+cmExportInstallPackageInfoGenerator::GetFileSetDirectory(
+  cmGeneratorTarget* gte, cmTargetExport const* te, cmFileSet* fileSet,
+  cm::optional<std::string> const& config)
+{
+  cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance());
+  auto cge =
+    ge.Parse(te->FileSetGenerators.at(fileSet->GetName())->GetDestination());
+
+  std::string const unescapedDest =
+    cge->Evaluate(gte->LocalGenerator, config.value_or(""), gte);
+  bool const isConfigDependent = cge->GetHadContextSensitiveCondition();
+
+  if (config && !isConfigDependent) {
+    return {};
+  }
+  if (!config && isConfigDependent) {
+    this->RequiresConfigFiles = true;
+    return {};
+  }
+
+  std::string const& type = fileSet->GetType();
+  if (config && (type == "CXX_MODULES"_s)) {
+    // C++ modules do not support interface file sets which are dependent
+    // upon the configuration.
+    cmMakefile* mf = gte->LocalGenerator->GetMakefile();
+    std::ostringstream e;
+    e << "The \"" << gte->GetName() << "\" target's interface file set \""
+      << fileSet->GetName() << "\" of type \"" << type
+      << "\" contains context-sensitive base file entries which is not "
+         "supported.";
+    mf->IssueMessage(MessageType::FATAL_ERROR, e.str());
+    return {};
+  }
+
+  cm::optional<std::string> dest = cmOutputConverter::EscapeForCMake(
+    unescapedDest, cmOutputConverter::WrapQuotes::NoWrap);
+
+  if (!cmSystemTools::FileIsFullPath(unescapedDest)) {
+    dest = cmStrCat("@prefix@/"_s, *dest);
+  }
+
+  return dest;
+}
+
+bool cmExportInstallPackageInfoGenerator::GenerateFileSetProperties(
+  Json::Value& component, cmGeneratorTarget* gte, cmTargetExport const* te,
+  cm::optional<std::string> config)
+{
+  std::set<std::string> seenIncludeDirectories;
+  for (auto const& name : gte->Target->GetAllInterfaceFileSets()) {
+    cmFileSet* fileSet = gte->Target->GetFileSet(name);
+
+    if (!fileSet) {
+      gte->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("File set \"", name,
+                 "\" is listed in interface file sets of ", gte->GetName(),
+                 " but has not been created"));
+      return false;
+    }
+
+    cm::optional<std::string> const& fileSetDirectory =
+      this->GetFileSetDirectory(gte, te, fileSet, config);
+
+    if (fileSet->GetType() == "HEADERS"_s) {
+      if (fileSetDirectory &&
+          !cm::contains(seenIncludeDirectories, *fileSetDirectory)) {
+        component["includes"].append(*fileSetDirectory);
+        seenIncludeDirectories.insert(*fileSetDirectory);
+      }
+    } else if (fileSet->GetType() == "CXX_MODULES"_s) {
+      /* TODO: Handle the CXX_MODULE directory */
+    }
+  }
+
+  return true;
+}
diff --git a/Source/cmExportInstallPackageInfoGenerator.h b/Source/cmExportInstallPackageInfoGenerator.h
index abdd015..0cb79c8 100644
--- a/Source/cmExportInstallPackageInfoGenerator.h
+++ b/Source/cmExportInstallPackageInfoGenerator.h
@@ -7,12 +7,20 @@
 #include <iosfwd>
 #include <string>
 
+#include <cm/optional>
+
 #include "cmExportInstallFileGenerator.h"
 #include "cmExportPackageInfoGenerator.h"
 
+class cmFileSet;
 class cmGeneratorTarget;
 class cmInstallExportGenerator;
 class cmPackageInfoArguments;
+class cmTargetExport;
+
+namespace Json {
+class Value;
+}
 
 /** \class cmExportInstallPackageInfoGenerator
  * \brief Generate files exporting targets from an install tree.
@@ -43,6 +51,8 @@
   std::string GetConfigImportFileGlob() const override;
 
 protected:
+  bool RequiresConfigFiles = false;
+
   std::string const& GetExportName() const override;
 
   // Implement virtual methods from the superclass.
@@ -60,4 +70,13 @@
 
   std::string GetCxxModulesDirectory() const override;
   // TODO: Generate C++ module info in a not-CMake-specific format.
+
+  cm::optional<std::string> GetFileSetDirectory(
+    cmGeneratorTarget* gte, cmTargetExport const* te, cmFileSet* fileSet,
+    cm::optional<std::string> const& config = {});
+
+  bool GenerateFileSetProperties(Json::Value& component,
+                                 cmGeneratorTarget* gte,
+                                 cmTargetExport const* te,
+                                 cm::optional<std::string> config = {});
 };
diff --git a/Source/cmExportPackageInfoGenerator.cxx b/Source/cmExportPackageInfoGenerator.cxx
index f2fbc28..4b17ac2 100644
--- a/Source/cmExportPackageInfoGenerator.cxx
+++ b/Source/cmExportPackageInfoGenerator.cxx
@@ -5,9 +5,11 @@
 #include <cstddef>
 #include <memory>
 #include <set>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
+#include <cm/optional>
 #include <cm/string_view>
 #include <cmext/algorithm>
 #include <cmext/string_view>
@@ -27,7 +29,6 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 #include "cmTarget.h"
-#include "cmValue.h"
 
 static std::string const kCPS_VERSION_STR = "0.13.0";
 
@@ -39,6 +40,8 @@
   , PackageVersionSchema(std::move(arguments.VersionSchema))
   , PackageDescription(std::move(arguments.Description))
   , PackageWebsite(std::move(arguments.Website))
+  , PackageLicense(std::move(arguments.License))
+  , DefaultLicense(std::move(arguments.DefaultLicense))
   , DefaultTargets(std::move(arguments.DefaultTargets))
   , DefaultConfigurations(std::move(arguments.DefaultConfigs))
 {
@@ -127,7 +130,8 @@
 
   SetProperty(package, "description", this->PackageDescription);
   SetProperty(package, "website", this->PackageWebsite);
-  // TODO: license
+  SetProperty(package, "license", this->PackageLicense);
+  SetProperty(package, "default_license", this->DefaultLicense);
 
   return package;
 }
@@ -143,15 +147,25 @@
       auto data = Json::Value{ Json::objectValue };
 
       // Add required components.
-      if (!requirement.second.empty()) {
+      if (!requirement.second.Components.empty()) {
         auto components = Json::Value{ Json::arrayValue };
-        for (std::string const& component : requirement.second) {
+        for (std::string const& component : requirement.second.Components) {
           components.append(component);
         }
         data["components"] = components;
       }
 
-      // TODO: version, hint
+      // Add additional dependency information.
+      if (requirement.second.Directory) {
+        auto hints = Json::Value{ Json::arrayValue };
+        hints.append(*requirement.second.Directory);
+        data["hints"] = hints;
+      }
+
+      if (requirement.second.Version) {
+        data["version"] = *requirement.second.Version;
+      }
+
       requirements[requirement.first] = data;
     }
   }
@@ -280,16 +294,24 @@
 
   if (linkedTarget->IsImported()) {
     // Target is imported from a found package.
-    auto pkgName = [linkedTarget]() -> std::string {
-      auto const& pkgStack = linkedTarget->Target->GetFindPackageStack();
+    using Package = cm::optional<std::pair<std::string, cmPackageInformation>>;
+    auto pkgInfo = [](cmTarget* t) -> Package {
+      cmFindPackageStack pkgStack = t->GetFindPackageStack();
       if (!pkgStack.Empty()) {
-        return pkgStack.Top().Name;
+        return std::make_pair(pkgStack.Top().Name, pkgStack.Top().PackageInfo);
       }
 
-      return linkedTarget->Target->GetProperty("EXPORT_FIND_PACKAGE_NAME");
-    }();
+      cmPackageInformation package;
+      std::string const pkgName =
+        t->GetSafeProperty("EXPORT_FIND_PACKAGE_NAME");
+      if (pkgName.empty()) {
+        return cm::nullopt;
+      }
 
-    if (pkgName.empty()) {
+      return std::make_pair(pkgName, package);
+    }(linkedTarget->Target);
+
+    if (!pkgInfo) {
       target->Makefile->IssueMessage(
         MessageType::FATAL_ERROR,
         cmStrCat("Target \"", target->GetName(),
@@ -298,6 +320,8 @@
       return false;
     }
 
+    std::string const& pkgName = pkgInfo->first;
+
     auto const& prefix = cmStrCat(pkgName, "::");
     if (!cmHasPrefix(linkedName, prefix)) {
       target->Makefile->IssueMessage(
@@ -311,8 +335,9 @@
 
     std::string component = linkedName.substr(prefix.length());
     this->LinkTargets.emplace(linkedName, cmStrCat(pkgName, ':', component));
-    // TODO: Record package version, hint.
-    this->Requirements[pkgName].emplace(std::move(component));
+    cmPackageInformation& req =
+      this->Requirements.insert(std::move(*pkgInfo)).first->second;
+    req.Components.emplace(std::move(component));
     return true;
   }
 
@@ -336,7 +361,7 @@
       this->LinkTargets.emplace(linkedName, cmStrCat(':', component));
     } else {
       this->LinkTargets.emplace(linkedName, cmStrCat(pkgName, ':', component));
-      this->Requirements[pkgName].emplace(std::move(component));
+      this->Requirements[pkgName].Components.emplace(std::move(component));
     }
     return true;
   }
diff --git a/Source/cmExportPackageInfoGenerator.h b/Source/cmExportPackageInfoGenerator.h
index fb7d79f..0614e27 100644
--- a/Source/cmExportPackageInfoGenerator.h
+++ b/Source/cmExportPackageInfoGenerator.h
@@ -6,13 +6,13 @@
 
 #include <iosfwd>
 #include <map>
-#include <set>
 #include <string>
 #include <vector>
 
 #include <cm/string_view>
 
 #include "cmExportFileGenerator.h"
+#include "cmFindPackageStack.h"
 #include "cmStateTypes.h"
 
 namespace Json {
@@ -110,9 +110,12 @@
   std::string const PackageVersionSchema;
   std::string const PackageDescription;
   std::string const PackageWebsite;
+  std::string const PackageLicense;
+  std::string const DefaultLicense;
+
   std::vector<std::string> DefaultTargets;
   std::vector<std::string> DefaultConfigurations;
 
   std::map<std::string, std::string> LinkTargets;
-  std::map<std::string, std::set<std::string>> Requirements;
+  std::map<std::string, cmPackageInformation> Requirements;
 };
diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx
index 6ae22db..216b1c6 100644
--- a/Source/cmFileAPI.cxx
+++ b/Source/cmFileAPI.cxx
@@ -29,6 +29,20 @@
 #include "cmTimestamp.h"
 #include "cmake.h"
 
+#if defined(__clang__) && defined(__has_warning)
+#  if __has_warning("-Wrange-loop-analysis")
+#    if defined(__apple_build_version__)
+#      if __apple_build_version__ < 13000000
+#        define CM_CLANG_SUPPRESS_WARN_RANGE_LOOP_ANALYSIS
+#      endif
+#    else
+#      if __clang_major__ < 11
+#        define CM_CLANG_SUPPRESS_WARN_RANGE_LOOP_ANALYSIS
+#      endif
+#    endif
+#  endif
+#endif
+
 cmFileAPI::cmFileAPI(cmake* cm)
   : CMakeInstance(cm)
 {
@@ -85,11 +99,18 @@
   }
 }
 
-std::vector<unsigned long> cmFileAPI::GetConfigureLogVersions()
+std::vector<unsigned int> cmFileAPI::GetConfigureLogVersions()
 {
-  std::vector<unsigned long> versions;
+  std::vector<unsigned int> versions;
   auto getConfigureLogVersions = [&versions](Query const& q) {
-    for (Object const& o : q.Known) {
+#ifdef CM_CLANG_SUPPRESS_WARN_RANGE_LOOP_ANALYSIS
+#  pragma clang diagnostic push
+#  pragma clang diagnostic ignored "-Wrange-loop-analysis"
+#endif
+    for (Object const o : q.Known) {
+#ifdef CM_CLANG_SUPPRESS_WARN_RANGE_LOOP_ANALYSIS
+#  pragma clang diagnostic pop
+#endif
       if (o.Kind == ObjectKind::ConfigureLog) {
         versions.emplace_back(o.Version);
       }
@@ -126,7 +147,7 @@
   std::vector<std::string> files;
   cmsys::Directory d;
   d.Load(dir);
-  for (unsigned long i = 0; i < d.GetNumberOfFiles(); ++i) {
+  for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i) {
     std::string f = d.GetFile(i);
     if (f != "." && f != "..") {
       files.push_back(std::move(f));
@@ -446,7 +467,14 @@
 Json::Value cmFileAPI::BuildReply(Query const& q)
 {
   Json::Value reply = Json::objectValue;
-  for (Object const& o : q.Known) {
+#ifdef CM_CLANG_SUPPRESS_WARN_RANGE_LOOP_ANALYSIS
+#  pragma clang diagnostic push
+#  pragma clang diagnostic ignored "-Wrange-loop-analysis"
+#endif
+  for (Object const o : q.Known) {
+#ifdef CM_CLANG_SUPPRESS_WARN_RANGE_LOOP_ANALYSIS
+#  pragma clang diagnostic pop
+#endif
     std::string const& name = ObjectName(o);
     reply[name] = this->BuildReplyEntry(o);
   }
@@ -457,7 +485,7 @@
   return reply;
 }
 
-Json::Value cmFileAPI::BuildReplyEntry(Object const& object)
+Json::Value cmFileAPI::BuildReplyEntry(Object object)
 {
   if (this->ReplyIndexFor != IndexFor::Success) {
     switch (object.Kind) {
@@ -481,7 +509,7 @@
   return e;
 }
 
-Json::Value const& cmFileAPI::AddReplyIndexObject(Object const& o)
+Json::Value const& cmFileAPI::AddReplyIndexObject(Object o)
 {
   Json::Value& indexEntry = this->ReplyIndexObjects[o];
   if (!indexEntry.isNull()) {
@@ -515,7 +543,7 @@
   return objectKindNames[static_cast<size_t>(kind)];
 }
 
-std::string cmFileAPI::ObjectName(Object const& o)
+std::string cmFileAPI::ObjectName(Object o)
 {
   std::string name = cmStrCat(ObjectKindName(o.Kind), "-v", o.Version);
   return name;
@@ -529,7 +557,7 @@
   return version;
 }
 
-Json::Value cmFileAPI::BuildObject(Object const& object)
+Json::Value cmFileAPI::BuildObject(Object object)
 {
   Json::Value value;
 
@@ -789,8 +817,10 @@
 
 // The "codemodel" object kind.
 
-// Update Help/manual/cmake-file-api.7.rst when updating this constant.
-static unsigned int const CodeModelV2Minor = 8;
+// Update the following files as well when updating this constant:
+//   Help/manual/cmake-file-api.7.rst
+//   Tests/RunCMake/FileAPI/codemodel-v2-check.py (check_objects())
+static unsigned int const CodeModelV2Minor = 9;
 
 void cmFileAPI::BuildClientRequestCodeModel(
   ClientRequest& r, std::vector<RequestVersion> const& versions)
@@ -807,9 +837,11 @@
   }
 }
 
-Json::Value cmFileAPI::BuildCodeModel(Object const& object)
+Json::Value cmFileAPI::BuildCodeModel(Object object)
 {
-  Json::Value codemodel = cmFileAPICodemodelDump(*this, object.Version);
+  assert(object.Version == 2);
+  Json::Value codemodel =
+    cmFileAPICodemodelDump(*this, object.Version, CodeModelV2Minor);
   codemodel["kind"] = this->ObjectKindName(object.Kind);
 
   Json::Value& version = codemodel["version"];
@@ -842,7 +874,7 @@
   }
 }
 
-Json::Value cmFileAPI::BuildConfigureLog(Object const& object)
+Json::Value cmFileAPI::BuildConfigureLog(Object object)
 {
   Json::Value configureLog = cmFileAPIConfigureLogDump(*this, object.Version);
   configureLog["kind"] = this->ObjectKindName(object.Kind);
@@ -876,7 +908,7 @@
   }
 }
 
-Json::Value cmFileAPI::BuildCache(Object const& object)
+Json::Value cmFileAPI::BuildCache(Object object)
 {
   Json::Value cache = cmFileAPICacheDump(*this, object.Version);
   cache["kind"] = this->ObjectKindName(object.Kind);
@@ -910,7 +942,7 @@
   }
 }
 
-Json::Value cmFileAPI::BuildCMakeFiles(Object const& object)
+Json::Value cmFileAPI::BuildCMakeFiles(Object object)
 {
   Json::Value cmakeFiles = cmFileAPICMakeFilesDump(*this, object.Version);
   cmakeFiles["kind"] = this->ObjectKindName(object.Kind);
@@ -944,7 +976,7 @@
   }
 }
 
-Json::Value cmFileAPI::BuildToolchains(Object const& object)
+Json::Value cmFileAPI::BuildToolchains(Object object)
 {
   Json::Value toolchains = cmFileAPIToolchainsDump(*this, object.Version);
   toolchains["kind"] = this->ObjectKindName(object.Kind);
@@ -980,7 +1012,7 @@
   }
 }
 
-Json::Value cmFileAPI::BuildInternalTest(Object const& object)
+Json::Value cmFileAPI::BuildInternalTest(Object object)
 {
   Json::Value test = Json::objectValue;
   test["kind"] = this->ObjectKindName(object.Kind);
diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h
index 5b639ce..2e25111 100644
--- a/Source/cmFileAPI.h
+++ b/Source/cmFileAPI.h
@@ -25,7 +25,7 @@
   void ReadQueries();
 
   /** Get the list of configureLog object kind versions requested.  */
-  std::vector<unsigned long> GetConfigureLogVersions();
+  std::vector<unsigned int> GetConfigureLogVersions();
 
   /** Identify the situation in which WriteReplies is called.  */
   enum class IndexFor
@@ -64,6 +64,9 @@
   bool AddProjectQuery(ObjectKind kind, unsigned majorVersion,
                        unsigned minorVersion);
 
+  /** Build a JSON object with major and minor fields.  */
+  static Json::Value BuildVersion(unsigned int major, unsigned int minor);
+
 private:
   cmake* CMakeInstance;
 
@@ -83,22 +86,19 @@
   struct Object
   {
     ObjectKind Kind;
-    unsigned long Version = 0;
-    friend bool operator<(Object const& l, Object const& r)
+    unsigned int Version = 0;
+    friend bool operator<(Object l, Object r)
     {
       if (l.Kind != r.Kind) {
         return l.Kind < r.Kind;
       }
       return l.Version < r.Version;
     }
-    friend bool operator==(Object const& l, Object const& r)
+    friend bool operator==(Object l, Object r)
     {
       return l.Kind == r.Kind && l.Version == r.Version;
     }
-    friend bool operator!=(Object const& l, Object const& r)
-    {
-      return !(l == r);
-    }
+    friend bool operator!=(Object l, Object r) { return !(l == r); }
   };
 
   /** Represent content of a query directory.  */
@@ -189,16 +189,14 @@
   Json::Value BuildReplyIndex();
   Json::Value BuildCMake();
   Json::Value BuildReply(Query const& q);
-  Json::Value BuildReplyEntry(Object const& object);
+  Json::Value BuildReplyEntry(Object object);
   static Json::Value BuildReplyError(std::string const& error);
-  Json::Value const& AddReplyIndexObject(Object const& o);
+  Json::Value const& AddReplyIndexObject(Object o);
 
   static char const* ObjectKindName(ObjectKind kind);
-  static std::string ObjectName(Object const& o);
+  static std::string ObjectName(Object o);
 
-  static Json::Value BuildVersion(unsigned int major, unsigned int minor);
-
-  Json::Value BuildObject(Object const& object);
+  Json::Value BuildObject(Object object);
 
   ClientRequests BuildClientRequests(Json::Value const& requests);
   ClientRequest BuildClientRequest(Json::Value const& request);
@@ -222,25 +220,25 @@
 
   void BuildClientRequestCodeModel(
     ClientRequest& r, std::vector<RequestVersion> const& versions);
-  Json::Value BuildCodeModel(Object const& object);
+  Json::Value BuildCodeModel(Object object);
 
   void BuildClientRequestConfigureLog(
     ClientRequest& r, std::vector<RequestVersion> const& versions);
-  Json::Value BuildConfigureLog(Object const& object);
+  Json::Value BuildConfigureLog(Object object);
 
   void BuildClientRequestCache(ClientRequest& r,
                                std::vector<RequestVersion> const& versions);
-  Json::Value BuildCache(Object const& object);
+  Json::Value BuildCache(Object object);
 
   void BuildClientRequestCMakeFiles(
     ClientRequest& r, std::vector<RequestVersion> const& versions);
-  Json::Value BuildCMakeFiles(Object const& object);
+  Json::Value BuildCMakeFiles(Object object);
 
   void BuildClientRequestToolchains(
     ClientRequest& r, std::vector<RequestVersion> const& versions);
-  Json::Value BuildToolchains(Object const& object);
+  Json::Value BuildToolchains(Object object);
 
   void BuildClientRequestInternalTest(
     ClientRequest& r, std::vector<RequestVersion> const& versions);
-  Json::Value BuildInternalTest(Object const& object);
+  Json::Value BuildInternalTest(Object object);
 };
diff --git a/Source/cmFileAPICMakeFiles.cxx b/Source/cmFileAPICMakeFiles.cxx
index 68c13e8..2bb2083 100644
--- a/Source/cmFileAPICMakeFiles.cxx
+++ b/Source/cmFileAPICMakeFiles.cxx
@@ -22,7 +22,7 @@
 class CMakeFiles
 {
   cmFileAPI& FileAPI;
-  unsigned long Version;
+  unsigned int Version;
   std::string CMakeModules;
   std::string const& TopSource;
   std::string const& TopBuild;
@@ -35,11 +35,11 @@
   Json::Value DumpGlobDependent(cmGlobCacheEntry const& entry);
 
 public:
-  CMakeFiles(cmFileAPI& fileAPI, unsigned long version);
+  CMakeFiles(cmFileAPI& fileAPI, unsigned int version);
   Json::Value Dump();
 };
 
-CMakeFiles::CMakeFiles(cmFileAPI& fileAPI, unsigned long version)
+CMakeFiles::CMakeFiles(cmFileAPI& fileAPI, unsigned int version)
   : FileAPI(fileAPI)
   , Version(version)
   , CMakeModules(cmSystemTools::GetCMakeRoot() + "/Modules")
@@ -150,7 +150,7 @@
 }
 }
 
-Json::Value cmFileAPICMakeFilesDump(cmFileAPI& fileAPI, unsigned long version)
+Json::Value cmFileAPICMakeFilesDump(cmFileAPI& fileAPI, unsigned int version)
 {
   CMakeFiles cmakeFiles(fileAPI, version);
   return cmakeFiles.Dump();
diff --git a/Source/cmFileAPICMakeFiles.h b/Source/cmFileAPICMakeFiles.h
index 06f6ff5..8e15f8e 100644
--- a/Source/cmFileAPICMakeFiles.h
+++ b/Source/cmFileAPICMakeFiles.h
@@ -9,4 +9,4 @@
 class cmFileAPI;
 
 extern Json::Value cmFileAPICMakeFilesDump(cmFileAPI& fileAPI,
-                                           unsigned long version);
+                                           unsigned int version);
diff --git a/Source/cmFileAPICache.cxx b/Source/cmFileAPICache.cxx
index 74b3aa5..10be5a1 100644
--- a/Source/cmFileAPICache.cxx
+++ b/Source/cmFileAPICache.cxx
@@ -19,7 +19,7 @@
 class Cache
 {
   cmFileAPI& FileAPI;
-  unsigned long Version;
+  unsigned int Version;
   cmState* State;
 
   Json::Value DumpEntries();
@@ -29,11 +29,11 @@
                                 std::string const& prop);
 
 public:
-  Cache(cmFileAPI& fileAPI, unsigned long version);
+  Cache(cmFileAPI& fileAPI, unsigned int version);
   Json::Value Dump();
 };
 
-Cache::Cache(cmFileAPI& fileAPI, unsigned long version)
+Cache::Cache(cmFileAPI& fileAPI, unsigned int version)
   : FileAPI(fileAPI)
   , Version(version)
   , State(this->FileAPI.GetCMakeInstance()->GetState())
@@ -101,7 +101,7 @@
 }
 }
 
-Json::Value cmFileAPICacheDump(cmFileAPI& fileAPI, unsigned long version)
+Json::Value cmFileAPICacheDump(cmFileAPI& fileAPI, unsigned int version)
 {
   Cache cache(fileAPI, version);
   return cache.Dump();
diff --git a/Source/cmFileAPICache.h b/Source/cmFileAPICache.h
index dc179fa..d480cc2 100644
--- a/Source/cmFileAPICache.h
+++ b/Source/cmFileAPICache.h
@@ -9,4 +9,4 @@
 class cmFileAPI;
 
 extern Json::Value cmFileAPICacheDump(cmFileAPI& fileAPI,
-                                      unsigned long version);
+                                      unsigned int version);
diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx
index 3d60412..c1650d8 100644
--- a/Source/cmFileAPICodemodel.cxx
+++ b/Source/cmFileAPICodemodel.cxx
@@ -223,21 +223,24 @@
 class Codemodel
 {
   cmFileAPI& FileAPI;
-  unsigned long Version;
+  unsigned int VersionMajor;
+  unsigned int VersionMinor;
 
   Json::Value DumpPaths();
   Json::Value DumpConfigurations();
   Json::Value DumpConfiguration(std::string const& config);
 
 public:
-  Codemodel(cmFileAPI& fileAPI, unsigned long version);
+  Codemodel(cmFileAPI& fileAPI, unsigned int versionMajor,
+            unsigned int versionMinor);
   Json::Value Dump();
 };
 
 class CodemodelConfig
 {
   cmFileAPI& FileAPI;
-  unsigned long Version;
+  unsigned int VersionMajor;
+  unsigned int VersionMinor;
   std::string const& Config;
   std::string TopSource;
   std::string TopBuild;
@@ -290,8 +293,8 @@
   Json::Value DumpMinimumCMakeVersion(cmStateSnapshot s);
 
 public:
-  CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
-                  std::string const& config);
+  CodemodelConfig(cmFileAPI& fileAPI, unsigned int versionMajor,
+                  unsigned int versionMinor, std::string const& config);
   Json::Value Dump();
 };
 
@@ -392,6 +395,8 @@
 class DirectoryObject
 {
   cmLocalGenerator const* LG = nullptr;
+  unsigned int VersionMajor;
+  unsigned int VersionMinor;
   std::string const& Config;
   TargetIndexMapType& TargetIndexMap;
   std::string TopSource;
@@ -409,7 +414,8 @@
                                 std::string const& toPath);
 
 public:
-  DirectoryObject(cmLocalGenerator const* lg, std::string const& config,
+  DirectoryObject(cmLocalGenerator const* lg, unsigned int versionMajor,
+                  unsigned int versionMinor, std::string const& config,
                   TargetIndexMapType& targetIndexMap);
   Json::Value Dump();
 };
@@ -417,6 +423,8 @@
 class Target
 {
   cmGeneratorTarget* GT;
+  unsigned int VersionMajor;
+  unsigned int VersionMinor;
   std::string const& Config;
   std::string TopSource;
   std::string TopBuild;
@@ -511,13 +519,16 @@
   Json::Value DumpDebugger();
 
 public:
-  Target(cmGeneratorTarget* gt, std::string const& config);
+  Target(cmGeneratorTarget* gt, unsigned int versionMajor,
+         unsigned int versionMinor, std::string const& config);
   Json::Value Dump();
 };
 
-Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned long version)
+Codemodel::Codemodel(cmFileAPI& fileAPI, unsigned int versionMajor,
+                     unsigned int versionMinor)
   : FileAPI(fileAPI)
-  , Version(version)
+  , VersionMajor(versionMajor)
+  , VersionMinor(versionMinor)
 {
 }
 
@@ -557,19 +568,21 @@
 
 Json::Value Codemodel::DumpConfiguration(std::string const& config)
 {
-  CodemodelConfig configuration(this->FileAPI, this->Version, config);
+  CodemodelConfig configuration(this->FileAPI, this->VersionMajor,
+                                this->VersionMinor, config);
   return configuration.Dump();
 }
 
-CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned long version,
+CodemodelConfig::CodemodelConfig(cmFileAPI& fileAPI, unsigned int versionMajor,
+                                 unsigned int versionMinor,
                                  std::string const& config)
   : FileAPI(fileAPI)
-  , Version(version)
+  , VersionMajor(versionMajor)
+  , VersionMinor(versionMinor)
   , Config(config)
   , TopSource(this->FileAPI.GetCMakeInstance()->GetHomeDirectory())
   , TopBuild(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory())
 {
-  static_cast<void>(this->Version);
 }
 
 Json::Value CodemodelConfig::Dump()
@@ -701,7 +714,7 @@
 Json::Value CodemodelConfig::DumpTarget(cmGeneratorTarget* gt,
                                         Json::ArrayIndex ti)
 {
-  Target t(gt, this->Config);
+  Target t(gt, this->VersionMajor, this->VersionMinor, this->Config);
   std::string prefix = "target-" + gt->GetName();
   if (!this->Config.empty()) {
     prefix += "-" + this->Config;
@@ -797,7 +810,8 @@
     prefix += "-" + this->Config;
   }
 
-  DirectoryObject dir(d.LocalGenerator, this->Config, this->TargetIndexMap);
+  DirectoryObject dir(d.LocalGenerator, this->VersionMajor, this->VersionMinor,
+                      this->Config, this->TargetIndexMap);
   return this->FileAPI.MaybeJsonFile(dir.Dump(), prefix);
 }
 
@@ -844,9 +858,13 @@
 }
 
 DirectoryObject::DirectoryObject(cmLocalGenerator const* lg,
+                                 unsigned int versionMajor,
+                                 unsigned int versionMinor,
                                  std::string const& config,
                                  TargetIndexMapType& targetIndexMap)
   : LG(lg)
+  , VersionMajor(versionMajor)
+  , VersionMinor(versionMinor)
   , Config(config)
   , TargetIndexMap(targetIndexMap)
   , TopSource(lg->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
@@ -859,6 +877,8 @@
 Json::Value DirectoryObject::Dump()
 {
   Json::Value directoryObject = Json::objectValue;
+  directoryObject["codemodelVersion"] =
+    cmFileAPI::BuildVersion(this->VersionMajor, this->VersionMinor);
   directoryObject["paths"] = this->DumpPaths();
   directoryObject["installers"] = this->DumpInstallers();
   directoryObject["backtraceGraph"] = this->Backtraces.Dump();
@@ -1186,8 +1206,11 @@
   return installPath;
 }
 
-Target::Target(cmGeneratorTarget* gt, std::string const& config)
+Target::Target(cmGeneratorTarget* gt, unsigned int versionMajor,
+               unsigned int versionMinor, std::string const& config)
   : GT(gt)
+  , VersionMajor(versionMajor)
+  , VersionMinor(versionMinor)
   , Config(config)
   , TopSource(gt->GetGlobalGenerator()->GetCMakeInstance()->GetHomeDirectory())
   , TopBuild(
@@ -1203,6 +1226,8 @@
 
   cmStateEnums::TargetType const type = this->GT->GetType();
 
+  target["codemodelVersion"] =
+    cmFileAPI::BuildVersion(this->VersionMajor, this->VersionMinor);
   target["name"] = this->GT->GetName();
   target["type"] = cmState::GetTargetTypeName(type);
   target["id"] = TargetId(this->GT, this->TopBuild);
@@ -2154,8 +2179,10 @@
   return debuggerInformation;
 }
 
-Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI, unsigned long version)
+Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI,
+                                   unsigned int versionMajor,
+                                   unsigned int versionMinor)
 {
-  Codemodel codemodel(fileAPI, version);
+  Codemodel codemodel(fileAPI, versionMajor, versionMinor);
   return codemodel.Dump();
 }
diff --git a/Source/cmFileAPICodemodel.h b/Source/cmFileAPICodemodel.h
index 6a3d7b2..55632ca 100644
--- a/Source/cmFileAPICodemodel.h
+++ b/Source/cmFileAPICodemodel.h
@@ -9,4 +9,5 @@
 class cmFileAPI;
 
 extern Json::Value cmFileAPICodemodelDump(cmFileAPI& fileAPI,
-                                          unsigned long version);
+                                          unsigned int majorVersion,
+                                          unsigned int minorVersion);
diff --git a/Source/cmFileAPIConfigureLog.cxx b/Source/cmFileAPIConfigureLog.cxx
index 3e5ba94..7cd3d97 100644
--- a/Source/cmFileAPIConfigureLog.cxx
+++ b/Source/cmFileAPIConfigureLog.cxx
@@ -13,17 +13,17 @@
 class ConfigureLog
 {
   cmFileAPI& FileAPI;
-  unsigned long Version;
+  unsigned int Version;
 
   Json::Value DumpPath();
   Json::Value DumpEventKindNames();
 
 public:
-  ConfigureLog(cmFileAPI& fileAPI, unsigned long version);
+  ConfigureLog(cmFileAPI& fileAPI, unsigned int version);
   Json::Value Dump();
 };
 
-ConfigureLog::ConfigureLog(cmFileAPI& fileAPI, unsigned long version)
+ConfigureLog::ConfigureLog(cmFileAPI& fileAPI, unsigned int version)
   : FileAPI(fileAPI)
   , Version(version)
 {
@@ -62,8 +62,7 @@
 }
 }
 
-Json::Value cmFileAPIConfigureLogDump(cmFileAPI& fileAPI,
-                                      unsigned long version)
+Json::Value cmFileAPIConfigureLogDump(cmFileAPI& fileAPI, unsigned int version)
 {
   ConfigureLog configureLog(fileAPI, version);
   return configureLog.Dump();
diff --git a/Source/cmFileAPIConfigureLog.h b/Source/cmFileAPIConfigureLog.h
index b290828..b1da1f8 100644
--- a/Source/cmFileAPIConfigureLog.h
+++ b/Source/cmFileAPIConfigureLog.h
@@ -9,4 +9,4 @@
 class cmFileAPI;
 
 extern Json::Value cmFileAPIConfigureLogDump(cmFileAPI& fileAPI,
-                                             unsigned long version);
+                                             unsigned int version);
diff --git a/Source/cmFileAPIToolchains.cxx b/Source/cmFileAPIToolchains.cxx
index 74d69bf..c156ca1 100644
--- a/Source/cmFileAPIToolchains.cxx
+++ b/Source/cmFileAPIToolchains.cxx
@@ -29,7 +29,7 @@
 class Toolchains
 {
   cmFileAPI& FileAPI;
-  unsigned long Version;
+  unsigned int Version;
 
   Json::Value DumpToolchains();
   Json::Value DumpToolchain(std::string const& lang);
@@ -41,11 +41,11 @@
                              ToolchainVariable const& variable);
 
 public:
-  Toolchains(cmFileAPI& fileAPI, unsigned long version);
+  Toolchains(cmFileAPI& fileAPI, unsigned int version);
   Json::Value Dump();
 };
 
-Toolchains::Toolchains(cmFileAPI& fileAPI, unsigned long version)
+Toolchains::Toolchains(cmFileAPI& fileAPI, unsigned int version)
   : FileAPI(fileAPI)
   , Version(version)
 {
@@ -143,7 +143,7 @@
 }
 }
 
-Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI, unsigned long version)
+Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI, unsigned int version)
 {
   Toolchains toolchains(fileAPI, version);
   return toolchains.Dump();
diff --git a/Source/cmFileAPIToolchains.h b/Source/cmFileAPIToolchains.h
index b6b48fb..b7676a8 100644
--- a/Source/cmFileAPIToolchains.h
+++ b/Source/cmFileAPIToolchains.h
@@ -9,4 +9,4 @@
 class cmFileAPI;
 
 extern Json::Value cmFileAPIToolchainsDump(cmFileAPI& fileAPI,
-                                           unsigned long version);
+                                           unsigned int version);
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 88f9f0c..057b3fa 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -3848,7 +3848,7 @@
   return true;
 }
 
-bool SetPermissions(std::string const& filename, mode_t const& perms,
+bool SetPermissions(std::string const& filename, mode_t perms,
                     cmExecutionStatus& status)
 {
   if (!cmSystemTools::SetPermissions(filename, perms)) {
@@ -3953,8 +3953,7 @@
 
     if (cmSystemTools::FileExists(i, true)) {
       bool success = true;
-      mode_t const& filePermissions =
-        parsedArgs.FilePermissions ? fperms : perms;
+      mode_t filePermissions = parsedArgs.FilePermissions ? fperms : perms;
       if (filePermissions) {
         success = SetPermissions(i, filePermissions, status);
       }
@@ -3965,7 +3964,7 @@
 
     else if (cmSystemTools::FileIsDirectory(i)) {
       bool success = true;
-      mode_t const& directoryPermissions =
+      mode_t directoryPermissions =
         parsedArgs.DirectoryPermissions ? dperms : perms;
       if (directoryPermissions) {
         success = SetPermissions(i, directoryPermissions, status);
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
index 65320aa..c848ed7 100644
--- a/Source/cmFileCopier.cxx
+++ b/Source/cmFileCopier.cxx
@@ -607,7 +607,7 @@
 
   // Copy the file.
   if (copy) {
-    auto copy_status = cmSystemTools::CopyAFile(fromFile, toFile, true);
+    auto copy_status = cmSystemTools::CopyAFile(fromFile, toFile);
     if (!copy_status) {
       std::ostringstream e;
       e << this->Name << " cannot copy file \"" << fromFile << "\" to \""
diff --git a/Source/cmFileTime.h b/Source/cmFileTime.h
index 52ecf50..7887bf1 100644
--- a/Source/cmFileTime.h
+++ b/Source/cmFileTime.h
@@ -22,10 +22,6 @@
   // unit time is 100 nanosecond
   static constexpr TimeType UtPerS = 10000000;
 #endif
-  cmFileTime() = default;
-  ~cmFileTime() = default;
-  cmFileTime(cmFileTime const&) = default;
-  cmFileTime& operator=(cmFileTime const&) = default;
 
   /**
    * @brief Loads the file time of fileName from the file system
@@ -36,34 +32,28 @@
   /**
    * @brief Return true if this is older than ftm
    */
-  bool Older(cmFileTime const& ftm) const
-  {
-    return (this->Time - ftm.Time) < 0;
-  }
+  bool Older(cmFileTime ftm) const { return (this->Time - ftm.Time) < 0; }
 
   /**
    * @brief Return true if this is newer than ftm
    */
-  bool Newer(cmFileTime const& ftm) const
-  {
-    return (ftm.Time - this->Time) < 0;
-  }
+  bool Newer(cmFileTime ftm) const { return (ftm.Time - this->Time) < 0; }
 
   /**
    * @brief Return true if this is the same as ftm
    */
-  bool Equal(cmFileTime const& ftm) const { return this->Time == ftm.Time; }
+  bool Equal(cmFileTime ftm) const { return this->Time == ftm.Time; }
 
   /**
    * @brief Return true if this is not the same as ftm
    */
-  bool Differ(cmFileTime const& ftm) const { return this->Time != ftm.Time; }
+  bool Differ(cmFileTime ftm) const { return this->Time != ftm.Time; }
 
   /**
    * @brief Compare file modification times.
    * @return -1, 0, +1 for this older, same, or newer than ftm.
    */
-  int Compare(cmFileTime const& ftm) const
+  int Compare(cmFileTime ftm) const
   {
     TimeType const diff = this->Time - ftm.Time;
     if (diff == 0) {
@@ -77,7 +67,7 @@
   /**
    * @brief Return true if this is at least a second older than ftm
    */
-  bool OlderS(cmFileTime const& ftm) const
+  bool OlderS(cmFileTime ftm) const
   {
     return (ftm.Time - this->Time) >= cmFileTime::UtPerS;
   }
@@ -85,7 +75,7 @@
   /**
    * @brief Return true if this is at least a second newer than ftm
    */
-  bool NewerS(cmFileTime const& ftm) const
+  bool NewerS(cmFileTime ftm) const
   {
     return (this->Time - ftm.Time) >= cmFileTime::UtPerS;
   }
@@ -93,7 +83,7 @@
   /**
    * @brief Return true if this is within the same second as ftm
    */
-  bool EqualS(cmFileTime const& ftm) const
+  bool EqualS(cmFileTime ftm) const
   {
     TimeType diff = this->Time - ftm.Time;
     if (diff < 0) {
@@ -105,7 +95,7 @@
   /**
    * @brief Return true if this is older or newer than ftm by at least a second
    */
-  bool DifferS(cmFileTime const& ftm) const
+  bool DifferS(cmFileTime ftm) const
   {
     TimeType diff = this->Time - ftm.Time;
     if (diff < 0) {
@@ -119,7 +109,7 @@
    * @return -1: this at least a second older, 0: this within the same second
    *         as ftm, +1: this at least a second newer than ftm.
    */
-  int CompareS(cmFileTime const& ftm) const
+  int CompareS(cmFileTime ftm) const
   {
     TimeType const diff = this->Time - ftm.Time;
     if (diff <= -cmFileTime::UtPerS) {
diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx
index 6201894..6c43c7a 100644
--- a/Source/cmFindPackageCommand.cxx
+++ b/Source/cmFindPackageCommand.cxx
@@ -28,6 +28,7 @@
 #include "cmDependencyProvider.h"
 #include "cmExecutionStatus.h"
 #include "cmExperimental.h"
+#include "cmFindPackageStack.h"
 #include "cmList.h"
 #include "cmListFileCache.h"
 #include "cmMakefile.h"
@@ -630,6 +631,12 @@
     return false;
   }
 
+  if (this->Makefile->GetStateSnapshot().GetUnwindState() ==
+      cmStateEnums::UNWINDING) {
+    this->SetError("called while already in an UNWIND state");
+    return false;
+  }
+
   // Lookup required version of CMake.
   if (cmValue const rv =
         this->Makefile->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) {
@@ -839,6 +846,14 @@
           cmStrCat("given invalid value for REGISTRY_VIEW: ", args[i]));
         return false;
       }
+    } else if (args[i] == "UNWIND_INCLUDE") {
+      if (this->Makefile->GetStateSnapshot().GetUnwindType() !=
+          cmStateEnums::CAN_UNWIND) {
+        this->SetError("called with UNWIND_INCLUDE in an invalid context");
+        return false;
+      }
+      this->ScopeUnwind = true;
+      doing = DoingNone;
     } else if (this->CheckCommonArgument(args[i])) {
       configArgs.push_back(i);
       doing = DoingNone;
@@ -1053,8 +1068,18 @@
       this->VersionMaxPatch, this->VersionMaxTweak);
   }
 
-  return this->FindPackage(this->BypassProvider ? std::vector<std::string>{}
-                                                : args);
+  bool result = this->FindPackage(
+    this->BypassProvider ? std::vector<std::string>{} : args);
+
+  std::string const foundVar = cmStrCat(this->Name, "_FOUND");
+  bool const isFound = this->Makefile->IsOn(foundVar) ||
+    this->Makefile->IsOn(cmSystemTools::UpperCase(foundVar));
+
+  if (this->ScopeUnwind && (!result || !isFound)) {
+    this->Makefile->GetStateSnapshot().SetUnwindState(cmStateEnums::UNWINDING);
+  }
+
+  return result;
 }
 
 bool cmFindPackageCommand::FindPackage(
@@ -1197,8 +1222,9 @@
   FlushDebugBufferOnExit flushDebugBufferOnExit(*this);
   PushPopRootPathStack pushPopRootPathStack(*this);
   SetRestoreFindDefinitions setRestoreFindDefinitions(*this);
-  cmMakefile::FindPackageStackRAII findPackageStackRAII(this->Makefile,
-                                                        this->Name);
+  cmFindPackageStackRAII findPackageStackRAII(this->Makefile, this->Name);
+
+  findPackageStackRAII.BindTop(this->CurrentPackageInfo);
 
   // See if we have been told to delegate to FetchContent or some other
   // redirected config package first. We have to check all names that
@@ -1246,6 +1272,8 @@
       this->Names.clear();
       this->Names.emplace_back(overrideName); // Force finding this one
       this->Variable = cmStrCat(this->Name, "_DIR");
+      this->CurrentPackageInfo->Directory = redirectsDir;
+      this->CurrentPackageInfo->Version = this->VersionFound;
       this->SetConfigDirCacheVariable(redirectsDir);
       break;
     }
@@ -1318,7 +1346,6 @@
   }
 
   this->AppendSuccessInformation();
-
   return loadedPackage;
 }
 
@@ -1947,6 +1974,8 @@
   std::string init;
   if (found) {
     init = cmSystemTools::GetFilenamePath(this->FileFound);
+    this->CurrentPackageInfo->Directory = init;
+    this->CurrentPackageInfo->Version = this->VersionFound;
   } else {
     init = this->Variable + "-NOTFOUND";
   }
@@ -2047,12 +2076,24 @@
   ITScope scope = this->GlobalScope ? ITScope::Global : ITScope::Local;
   cmMakefile::SetGlobalTargetImportScope globScope(this->Makefile, scope);
 
-  if (this->Makefile->ReadDependentFile(f, noPolicyScope)) {
-    return true;
+  auto oldUnwind = this->Makefile->GetStateSnapshot().GetUnwindType();
+
+  // This allows child snapshots to inherit the CAN_UNWIND state from us, we'll
+  // reset it immediately after the dependent file is done
+  this->Makefile->GetStateSnapshot().SetUnwindType(cmStateEnums::CAN_UNWIND);
+  bool result = this->Makefile->ReadDependentFile(f, noPolicyScope);
+
+  this->Makefile->GetStateSnapshot().SetUnwindType(oldUnwind);
+  this->Makefile->GetStateSnapshot().SetUnwindState(
+    cmStateEnums::NOT_UNWINDING);
+
+  if (!result) {
+    std::string const e =
+      cmStrCat("Error reading CMake code from \"", f, "\".");
+    this->SetError(e);
   }
-  std::string const e = cmStrCat("Error reading CMake code from \"", f, "\".");
-  this->SetError(e);
-  return false;
+
+  return result;
 }
 
 bool cmFindPackageCommand::ReadPackage()
diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h
index 10448a8..ff8ff27 100644
--- a/Source/cmFindPackageCommand.h
+++ b/Source/cmFindPackageCommand.h
@@ -37,6 +37,7 @@
 class cmMakefile;
 class cmPackageState;
 class cmSearchPath;
+class cmPackageInformation;
 
 /** \class cmFindPackageCommand
  * \brief Load settings from an external project.
@@ -276,6 +277,7 @@
   bool PolicyScope = true;
   bool GlobalScope = false;
   bool RegistryViewDefined = false;
+  bool ScopeUnwind = false;
   std::string LibraryArchitecture;
   std::vector<std::string> Names;
   std::set<std::string> IgnoredPaths;
@@ -285,6 +287,8 @@
   std::set<std::string> OptionalComponents;
   std::set<std::string> RequiredTargets;
   std::string DebugBuffer;
+  cmPackageInformation* CurrentPackageInfo;
+
   enum class SearchResult
   {
     InsufficientVersion,
@@ -334,10 +338,10 @@
 
   class FlushDebugBufferOnExit;
 
-  /*! the selected sortOrder (None by default)*/
-  SortOrderType SortOrder = None;
-  /*! the selected sortDirection (Asc by default)*/
-  SortDirectionType SortDirection = Asc;
+  /*! the selected sortOrder (Natural by default)*/
+  SortOrderType SortOrder = Natural;
+  /*! the selected sortDirection (Dec by default)*/
+  SortDirectionType SortDirection = Dec;
 
   struct ConfigFileInfo
   {
diff --git a/Source/cmFindPackageStack.cxx b/Source/cmFindPackageStack.cxx
index 0803049..6f5045a 100644
--- a/Source/cmFindPackageStack.cxx
+++ b/Source/cmFindPackageStack.cxx
@@ -3,5 +3,13 @@
 #define cmFindPackageStack_cxx
 #include "cmFindPackageStack.h"
 
-#include "cmConstStack.tcc" // IWYU pragma: keep
-template class cmConstStack<cmFindPackageCall, cmFindPackageStack>;
+#include "cmStack.tcc" // IWYU pragma: keep
+template class cmStack<cmFindPackageCall, cmFindPackageStack>;
+
+template cmFindPackageCall&
+cmStack<cmFindPackageCall, cmFindPackageStack>::Top<true>();
+
+cmFindPackageCall const& cmFindPackageStack::Top() const
+{
+  return this->cmStack::Top();
+}
diff --git a/Source/cmFindPackageStack.h b/Source/cmFindPackageStack.h
index e281b51..e7fb9a6 100644
--- a/Source/cmFindPackageStack.h
+++ b/Source/cmFindPackageStack.h
@@ -5,9 +5,32 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <memory>
+#include <set>
 #include <string>
 
-#include "cmConstStack.h"
+#include <cm/optional>
+
+#include "cmStack.h"
+
+class cmMakefile;
+
+/**
+ * This data represents the actual contents of find_package
+ * <PACKAGE>-Config.cmake or <PACKAGE>.cps file, and not what is passed
+ * to the find_package command. They can be the same, but it is not guaranteed.
+ */
+
+class cmPackageInformation
+{
+public:
+  cm::optional<std::string> Directory;
+  cm::optional<std::string> Version;
+  cm::optional<std::string> Description;
+  cm::optional<std::string> License;
+  cm::optional<std::string> Website;
+  cm::optional<std::string> PackageUrl;
+  std::set<std::string> Components;
+};
 
 /**
  * Represents one call to find_package.
@@ -15,19 +38,53 @@
 class cmFindPackageCall
 {
 public:
-  std::string Name;
+  std::string const Name;
+  cmPackageInformation PackageInfo;
   unsigned int Index;
 };
 
 /**
+ * RAII type to manage the find_package call stack.
+ */
+// Note: implemented in cmMakefile.cxx
+class cmFindPackageStackRAII
+{
+  cmMakefile* Makefile;
+  cmPackageInformation** Value = nullptr;
+
+public:
+  cmFindPackageStackRAII(cmMakefile* mf, std::string const& pkg);
+  ~cmFindPackageStackRAII();
+
+  cmFindPackageStackRAII(cmFindPackageStackRAII const&) = delete;
+  cmFindPackageStackRAII& operator=(cmFindPackageStackRAII const&) = delete;
+
+  /** Get a mutable pointer to the top of the stack.
+      The pointer is invalidated if BindTop is called again or when the
+      cmFindPackageStackRAII goes out of scope.  */
+  void BindTop(cmPackageInformation*& value);
+};
+
+/**
  * Represents a stack of find_package calls with efficient value semantics.
  */
 class cmFindPackageStack
-  : public cmConstStack<cmFindPackageCall, cmFindPackageStack>
+  : protected cmStack<cmFindPackageCall, cmFindPackageStack>
 {
-  using cmConstStack::cmConstStack;
-  friend class cmConstStack<cmFindPackageCall, cmFindPackageStack>;
+  using cmStack::cmStack;
+  friend cmFindPackageStack::Base;
+  friend class cmFindPackageStackRAII;
+
+public:
+  using cmStack::Push;
+  using cmStack::Pop;
+  using cmStack::Empty;
+
+  cmFindPackageCall const& Top() const;
 };
 #ifndef cmFindPackageStack_cxx
-extern template class cmConstStack<cmFindPackageCall, cmFindPackageStack>;
+extern template class cmStack<cmFindPackageCall, cmFindPackageStack>;
+
+extern template cmFindPackageCall&
+cmStack<cmFindPackageCall, cmFindPackageStack>::Top<true>();
 #endif
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index f6bcb57..006594a 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -217,7 +217,7 @@
 }
 
 static void prefixItems(std::string const& content, std::string& result,
-                        cm::string_view const& prefix)
+                        cm::string_view prefix)
 {
   std::vector<std::string> entries;
   cmGeneratorExpression::Split(content, entries);
@@ -404,8 +404,7 @@
   return extractAllGeneratorExpressions(input, &collected);
 }
 
-cm::string_view::size_type cmGeneratorExpression::Find(
-  cm::string_view const& input)
+cm::string_view::size_type cmGeneratorExpression::Find(cm::string_view input)
 {
   cm::string_view::size_type const openpos = input.find("$<");
   if (openpos != cm::string_view::npos &&
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index e5269b1..bda35f4 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -70,7 +70,7 @@
   static void Split(std::string const& input,
                     std::vector<std::string>& output);
 
-  static cm::string_view::size_type Find(cm::string_view const& input);
+  static cm::string_view::size_type Find(cm::string_view input);
 
   static bool IsValidTargetName(std::string const& input);
 
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 90bb06b..220fbab 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -702,7 +702,7 @@
 }
 bool CheckPathParameters(cmGeneratorExpressionContext* ctx,
                          GeneratorExpressionContent const* cnt,
-                         cm::string_view option, Arguments const& args,
+                         cm::string_view option, Arguments args,
                          int required = 1)
 {
   return CheckPathParametersEx(ctx, cnt, option, args.size(), required);
@@ -1190,7 +1190,7 @@
 }
 inline bool CheckListParameters(cmGeneratorExpressionContext* ctx,
                                 GeneratorExpressionContent const* cnt,
-                                cm::string_view option, Arguments const& args,
+                                cm::string_view option, Arguments args,
                                 int required = 1)
 {
   return CheckListParametersEx(ctx, cnt, option, args.size(), required);
@@ -1225,7 +1225,7 @@
 
 bool GetNumericArguments(
   cmGeneratorExpressionContext* ctx, GeneratorExpressionContent const* cnt,
-  Arguments const& args, std::vector<cmList::index_type>& indexes,
+  Arguments args, std::vector<cmList::index_type>& indexes,
   cmList::ExpandElements expandElements = cmList::ExpandElements::No)
 {
   using IndexRange = cmRange<Arguments::const_iterator>;
@@ -2226,11 +2226,11 @@
     if (parameters.empty()) {
       return configurationNode.Evaluate(parameters, context, content, nullptr);
     }
-    static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
-    if (!configValidator.find(parameters.front())) {
-    }
 
     context->HadContextSensitiveCondition = true;
+
+    // First, validate our arguments.
+    static cmsys::RegularExpression configValidator("^[A-Za-z0-9_]*$");
     bool firstParam = true;
     for (auto const& param : parameters) {
       if (!configValidator.find(param)) {
@@ -2250,41 +2250,109 @@
         context->LG->GetCMakeInstance()->IssueMessage(
           MessageType::WARNING, e.str(), context->Backtrace);
       }
-
       firstParam = false;
-      if (context->Config.empty()) {
-        if (param.empty()) {
+    }
+
+    // Determine the context(s) in which the expression should be evaluated. If
+    // CMPxxxx is NEW, the context is exactly one of the imported target's
+    // selected configuration, if applicable, or the consuming target's
+    // configuration, otherwise.
+    //
+    // If CMPxxxx is OLD, we evaluate first in the context of the consuming
+    // target, then, if the consumed target is imported, we evaluate based on
+    // the mapped configurations (this logic is... problematic; see comment
+    // below), then finally based on the selected configuration of the imported
+    // target.
+    bool const targetIsImported =
+      (context->CurrentTarget && context->CurrentTarget->IsImported());
+    bool const oldPolicy = [&] {
+      if (!targetIsImported) {
+        // For non-imported targets, there is no behavior difference between
+        // the OLD and NEW policy.
+        return false;
+      }
+      cmTarget const* const t = context->CurrentTarget->Target;
+      if (t->GetOrigin() == cmTarget::Origin::Cps) {
+        // Generator expressions appearing on targets imported from CPS should
+        // always be evaluated according to the selected configuration of the
+        // imported target, i.e. the NEW policy.
+        return false;
+      }
+      switch (context->HeadTarget->GetPolicyStatusCMP0199()) {
+        case cmPolicies::WARN:
+          if (context->LG->GetMakefile()->PolicyOptionalWarningEnabled(
+                "CMAKE_POLICY_WARNING_CMP0199")) {
+            std::string const err =
+              cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0199),
+                       "\nEvaluation of $<CONFIG> for imported target  \"",
+                       context->CurrentTarget->GetName(), "\", used by \"",
+                       context->HeadTarget->GetName(),
+                       "\", may match multiple configurations.\n");
+            context->LG->GetCMakeInstance()->IssueMessage(
+              MessageType ::AUTHOR_WARNING, err, context->Backtrace);
+          }
+          CM_FALLTHROUGH;
+        case cmPolicies::OLD:
+          return true;
+        case cmPolicies::NEW:
+          return false;
+      }
+
+      // Should be unreachable
+      assert(false);
+      return false;
+    }();
+
+    if (!targetIsImported || oldPolicy) {
+      // Does the consuming target's configuration match any of the arguments?
+      for (auto const& param : parameters) {
+        if (context->Config.empty()) {
+          if (param.empty()) {
+            return "1";
+          }
+        } else if (cmsysString_strcasecmp(param.c_str(),
+                                          context->Config.c_str()) == 0) {
           return "1";
         }
-      } else if (cmsysString_strcasecmp(param.c_str(),
-                                        context->Config.c_str()) == 0) {
-        return "1";
       }
     }
 
-    if (context->CurrentTarget && context->CurrentTarget->IsImported()) {
+    if (targetIsImported) {
       cmValue loc = nullptr;
       cmValue imp = nullptr;
       std::string suffix;
       if (context->CurrentTarget->Target->GetMappedConfig(context->Config, loc,
                                                           imp, suffix)) {
-        // This imported target has an appropriate location
-        // for this (possibly mapped) config.
-        // Check if there is a proper config mapping for the tested config.
-        cmList mappedConfigs;
-        std::string mapProp = cmStrCat(
-          "MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(context->Config));
-        if (cmValue mapValue = context->CurrentTarget->GetProperty(mapProp)) {
-          mappedConfigs.assign(cmSystemTools::UpperCase(*mapValue));
+        if (oldPolicy) {
+          // If the target has a MAP_IMPORTED_CONFIG_<CONFIG> property for the
+          // consumer's <CONFIG>, match *any* config in that list, regardless
+          // of whether it's valid or of what GetMappedConfig actually picked.
+          // This will result in $<CONFIG> producing '1' for multiple configs,
+          // and is almost certainly wrong, but it's what CMake did for a very
+          // long time, and... Hyrum's Law.
+          cmList mappedConfigs;
+          std::string mapProp = cmStrCat(
+            "MAP_IMPORTED_CONFIG_", cmSystemTools::UpperCase(context->Config));
+          if (cmValue mapValue =
+                context->CurrentTarget->GetProperty(mapProp)) {
+            mappedConfigs.assign(cmSystemTools::UpperCase(*mapValue));
 
-          for (auto const& param : parameters) {
-            if (cm::contains(mappedConfigs, cmSystemTools::UpperCase(param))) {
-              return "1";
+            for (auto const& param : parameters) {
+              if (cm::contains(mappedConfigs,
+                               cmSystemTools::UpperCase(param))) {
+                return "1";
+              }
             }
+
+            return "0";
           }
-        } else if (!suffix.empty()) {
-          // There is no explicit mapping for the tested config, so use
-          // the configuration of the imported location that was selected.
+        }
+
+        // This imported target has an appropriate location for this (possibly
+        // mapped) config.
+        if (!suffix.empty()) {
+          // Use the (possibly mapped) configuration of the imported location
+          // that was selected.
           for (auto const& param : parameters) {
             if (cmStrCat('_', cmSystemTools::UpperCase(param)) == suffix) {
               return "1";
@@ -2293,6 +2361,7 @@
         }
       }
     }
+
     return "0";
   }
 } configurationTestNode;
@@ -2561,6 +2630,146 @@
   }
 } linkLanguageAndIdNode;
 
+struct CompilerLinkerIdNode : public cmGeneratorExpressionNode
+{
+  CompilerLinkerIdNode(char const* lang)
+    : Language(lang)
+  {
+  }
+
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters,
+    cmGeneratorExpressionContext* context,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    if (!context->HeadTarget) {
+      reportError(
+        context, content->GetOriginalExpression(),
+        cmStrCat(
+          "$<", this->Language,
+          "_COMPILER_LINKER_ID> may only be used with binary targets. It may "
+          "not be used with add_custom_command or add_custom_target."));
+      return {};
+    }
+    return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+                                      this->Language);
+  }
+
+  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
+                                   cmGeneratorExpressionContext* context,
+                                   GeneratorExpressionContent const* content,
+                                   cmGeneratorExpressionDAGChecker* /*unused*/,
+                                   std::string const& lang) const
+  {
+    std::string const& compilerLinkerId =
+      context->LG->GetMakefile()->GetSafeDefinition(
+        cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_ID"));
+    if (parameters.empty()) {
+      return compilerLinkerId;
+    }
+    if (compilerLinkerId.empty()) {
+      return parameters.front().empty() ? "1" : "0";
+    }
+    static cmsys::RegularExpression compilerLinkerIdValidator(
+      "^[A-Za-z0-9_]*$");
+
+    for (auto const& param : parameters) {
+      if (!compilerLinkerIdValidator.find(param)) {
+        reportError(context, content->GetOriginalExpression(),
+                    "Expression syntax not recognized.");
+        return std::string();
+      }
+
+      if (param == compilerLinkerId) {
+        return "1";
+      }
+    }
+    return "0";
+  }
+
+  char const* const Language;
+};
+
+static CompilerLinkerIdNode const cCompilerLinkerIdNode("C"),
+  cxxCompilerLinkerIdNode("CXX"), cudaCompilerLinkerIdNode("CUDA"),
+  objcCompilerLinkerIdNode("OBJC"), objcxxCompilerLinkerIdNode("OBJCXX"),
+  fortranCompilerLinkerIdNode("Fortran"), hipCompilerLinkerIdNode("HIP");
+
+struct CompilerLinkerFrontendVariantNode : public cmGeneratorExpressionNode
+{
+  CompilerLinkerFrontendVariantNode(char const* lang)
+    : Language(lang)
+  {
+  }
+
+  int NumExpectedParameters() const override { return ZeroOrMoreParameters; }
+
+  std::string Evaluate(
+    std::vector<std::string> const& parameters,
+    cmGeneratorExpressionContext* context,
+    GeneratorExpressionContent const* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    if (!context->HeadTarget) {
+      reportError(
+        context, content->GetOriginalExpression(),
+        cmStrCat(
+          "$<", this->Language,
+          "_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary "
+          "targets. It may not be used with add_custom_command or "
+          "add_custom_target."));
+      return {};
+    }
+    return this->EvaluateWithLanguage(parameters, context, content, dagChecker,
+                                      this->Language);
+  }
+
+  std::string EvaluateWithLanguage(std::vector<std::string> const& parameters,
+                                   cmGeneratorExpressionContext* context,
+                                   GeneratorExpressionContent const* content,
+                                   cmGeneratorExpressionDAGChecker* /*unused*/,
+                                   std::string const& lang) const
+  {
+    std::string const& compilerLinkerFrontendVariant =
+      context->LG->GetMakefile()->GetSafeDefinition(
+        cmStrCat("CMAKE_", lang, "_COMPILER_LINKER_FRONTEND_VARIANT"));
+    if (parameters.empty()) {
+      return compilerLinkerFrontendVariant;
+    }
+    if (compilerLinkerFrontendVariant.empty()) {
+      return parameters.front().empty() ? "1" : "0";
+    }
+    static cmsys::RegularExpression compilerLinkerFrontendVariantValidator(
+      "^[A-Za-z0-9_]*$");
+
+    for (auto const& param : parameters) {
+      if (!compilerLinkerFrontendVariantValidator.find(param)) {
+        reportError(context, content->GetOriginalExpression(),
+                    "Expression syntax not recognized.");
+        return {};
+      }
+      if (param == compilerLinkerFrontendVariant) {
+        return "1";
+      }
+    }
+    return "0";
+  }
+
+  char const* const Language;
+};
+
+static CompilerLinkerFrontendVariantNode const
+  cCompilerLinkerFrontendVariantNode("C"),
+  cxxCompilerLinkerFrontendVariantNode("CXX"),
+  cudaCompilerLinkerFrontendVariantNode("CUDA"),
+  objcCompilerLinkerFrontendVariantNode("OBJC"),
+  objcxxCompilerLinkerFrontendVariantNode("OBJCXX"),
+  fortranCompilerLinkerFrontendVariantNode("Fortran"),
+  hipCompilerLinkerFrontendVariantNode("HIP");
+
 static const struct LinkLibraryNode : public cmGeneratorExpressionNode
 {
   LinkLibraryNode() {} // NOLINT(modernize-use-equals-default)
@@ -4641,6 +4850,27 @@
     { "COMPILE_LANGUAGE", &languageNode },
     { "LINK_LANG_AND_ID", &linkLanguageAndIdNode },
     { "LINK_LANGUAGE", &linkLanguageNode },
+    { "C_COMPILER_LINKER_ID", &cCompilerLinkerIdNode },
+    { "CXX_COMPILER_LINKER_ID", &cxxCompilerLinkerIdNode },
+    { "OBJC_COMPILER_LINKER_ID", &objcCompilerLinkerIdNode },
+    { "OBJCXX_COMPILER_LINKER_ID", &objcxxCompilerLinkerIdNode },
+    { "CUDA_COMPILER_LINKER_ID", &cudaCompilerLinkerIdNode },
+    { "Fortran_COMPILER_LINKER_ID", &fortranCompilerLinkerIdNode },
+    { "HIP_COMPILER_LINKER_ID", &hipCompilerLinkerIdNode },
+    { "C_COMPILER_LINKER_FRONTEND_VARIANT",
+      &cCompilerLinkerFrontendVariantNode },
+    { "CXX_COMPILER_LINKER_FRONTEND_VARIANT",
+      &cxxCompilerLinkerFrontendVariantNode },
+    { "CUDA_COMPILER_LINKER_FRONTEND_VARIANT",
+      &cudaCompilerLinkerFrontendVariantNode },
+    { "OBJC_COMPILER_LINKER_FRONTEND_VARIANT",
+      &objcCompilerLinkerFrontendVariantNode },
+    { "OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT",
+      &objcxxCompilerLinkerFrontendVariantNode },
+    { "Fortran_COMPILER_LINKER_FRONTEND_VARIANT",
+      &fortranCompilerLinkerFrontendVariantNode },
+    { "HIP_COMPILER_LINKER_FRONTEND_VARIANT",
+      &hipCompilerLinkerFrontendVariantNode },
     { "LINK_LIBRARY", &linkLibraryNode },
     { "LINK_GROUP", &linkGroupNode },
     { "HOST_LINK", &hostLinkNode },
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 60df703..dc29ca0 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -45,6 +45,7 @@
 #include "cmStandardLevel.h"
 #include "cmStandardLevelResolver.h"
 #include "cmState.h"
+#include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSyntheticTargetCache.h"
 #include "cmSystemTools.h"
@@ -1008,6 +1009,10 @@
           cmLinkItem(i.Value.first, i.Value.second, i.Backtrace));
       }
     }
+    if (cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget()) {
+      this->UtilityItems.insert(
+        cmLinkItem(reuseTarget, false, cmListFileBacktrace()));
+    }
   }
   return this->UtilityItems;
 }
@@ -1269,6 +1274,12 @@
 std::string cmGeneratorTarget::GetCompilePDBName(
   std::string const& config) const
 {
+  if (cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget()) {
+    if (reuseTarget != this) {
+      return reuseTarget->GetCompilePDBName(config);
+    }
+  }
+
   // Check for a per-configuration output directory target property.
   std::string configUpper = cmSystemTools::UpperCase(config);
   std::string configProp = cmStrCat("COMPILE_PDB_NAME_", configUpper);
@@ -1290,6 +1301,14 @@
     return components.prefix + pdbName + ".pdb";
   }
 
+  // If the target is PCH-reused, we need a stable name for the PDB file so
+  // that reusing targets can construct a stable name for it.
+  if (this->PchReused) {
+    NameComponents const& components = GetFullNameInternalComponents(
+      config, cmStateEnums::RuntimeBinaryArtifact);
+    return cmStrCat(components.prefix, this->GetName(), ".pdb");
+  }
+
   return "";
 }
 
@@ -2340,6 +2359,7 @@
     vars.Object = sfVars.ObjectFileDir.c_str();
     vars.ObjectDir = sfVars.ObjectDir.c_str();
     vars.ObjectFileDir = sfVars.ObjectFileDir.c_str();
+    vars.TargetSupportDir = sfVars.TargetSupportDir.c_str();
     vars.Flags = PlaceholderFlags.c_str();
     vars.DependencyFile = sfVars.DependencyFile.c_str();
     vars.DependencyTarget = sfVars.DependencyTarget.c_str();
@@ -2420,12 +2440,16 @@
 
   // Object settings.
   {
+    std::string const targetSupportDir = lg->MaybeRelativeToTopBinDir(
+      gg->ConvertToOutputPath(this->GetCMFSupportDirectory()));
     std::string const objectDir = gg->ConvertToOutputPath(
       cmStrCat(this->GetSupportDirectory(), gg->GetConfigDirectory(config)));
     std::string const objectFileName = this->GetObjectName(sf);
     std::string const objectFilePath =
       cmStrCat(objectDir, '/', objectFileName);
 
+    vars.TargetSupportDir =
+      lg->ConvertToOutputFormat(targetSupportDir, cmOutputConverter::SHELL);
     vars.ObjectDir =
       lg->ConvertToOutputFormat(objectDir, cmOutputConverter::SHELL);
     vars.ObjectFileDir =
@@ -2799,6 +2823,122 @@
   return cmSystemTools::CollapseFullPath(path);
 }
 
+struct CycleWatcher
+{
+  CycleWatcher(bool& flag)
+    : Flag(flag)
+  {
+    this->Flag = true;
+  }
+  ~CycleWatcher() { this->Flag = false; }
+  bool& Flag;
+};
+
+cmGeneratorTarget const* cmGeneratorTarget::GetPchReuseTarget() const
+{
+  if (this->ComputingPchReuse) {
+    // TODO: Get the full cycle.
+    if (!this->PchReuseCycleDetected) {
+      this->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Circular PCH reuse target involving '", this->GetName(),
+                 '\''));
+    }
+    this->PchReuseCycleDetected = true;
+    return nullptr;
+  }
+  CycleWatcher watch(this->ComputingPchReuse);
+  (void)watch;
+  cmValue pchReuseFrom = this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+  if (!pchReuseFrom) {
+    return nullptr;
+  }
+  cmGeneratorTarget const* generatorTarget =
+    this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
+  if (!generatorTarget) {
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat(
+        "Target \"", *pchReuseFrom, "\" for the \"", this->GetName(),
+        R"(" target's "PRECOMPILE_HEADERS_REUSE_FROM" property does not exist.)"));
+  }
+  if (this->GetProperty("PRECOMPILE_HEADERS").IsOn()) {
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("PRECOMPILE_HEADERS property is already set on target (\"",
+               this->GetName(), "\")\n"));
+  }
+
+  if (generatorTarget) {
+    if (generatorTarget->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
+      this->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat(
+          "Target \"", *pchReuseFrom, "\" for the \"", this->GetName(),
+          R"(" target's "PRECOMPILE_HEADERS_REUSE_FROM" property has set "DISABLE_PRECOMPILE_HEADERS".)"));
+      return nullptr;
+    }
+
+    if (auto const* recurseReuseTarget =
+          generatorTarget->GetPchReuseTarget()) {
+      return recurseReuseTarget;
+    }
+  }
+  return generatorTarget;
+}
+
+cmGeneratorTarget* cmGeneratorTarget::GetPchReuseTarget()
+{
+  if (this->ComputingPchReuse) {
+    // TODO: Get the full cycle.
+    if (!this->PchReuseCycleDetected) {
+      this->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Circular PCH reuse target involving '", this->GetName(),
+                 '\''));
+    }
+    this->PchReuseCycleDetected = true;
+    return nullptr;
+  }
+  CycleWatcher watch(this->ComputingPchReuse);
+  (void)watch;
+  cmValue pchReuseFrom = this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+  if (!pchReuseFrom) {
+    return nullptr;
+  }
+  cmGeneratorTarget* generatorTarget =
+    this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
+  if (!generatorTarget) {
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat(
+        "Target \"", *pchReuseFrom, "\" for the \"", this->GetName(),
+        R"(" target's "PRECOMPILE_HEADERS_REUSE_FROM" property does not exist.)"));
+  }
+  if (this->GetProperty("PRECOMPILE_HEADERS").IsOn()) {
+    this->Makefile->IssueMessage(
+      MessageType::FATAL_ERROR,
+      cmStrCat("PRECOMPILE_HEADERS property is already set on target (\"",
+               this->GetName(), "\")\n"));
+  }
+
+  if (generatorTarget) {
+    if (generatorTarget->GetPropertyAsBool("DISABLE_PRECOMPILE_HEADERS")) {
+      this->Makefile->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat(
+          "Target \"", *pchReuseFrom, "\" for the \"", this->GetName(),
+          R"(" target's "PRECOMPILE_HEADERS_REUSE_FROM" property has set "DISABLE_PRECOMPILE_HEADERS".)"));
+      return nullptr;
+    }
+
+    if (auto* recurseReuseTarget = generatorTarget->GetPchReuseTarget()) {
+      return recurseReuseTarget;
+    }
+  }
+  return generatorTarget;
+}
+
 std::vector<std::string> cmGeneratorTarget::GetPchArchs(
   std::string const& config, std::string const& lang) const
 {
@@ -2826,24 +2966,22 @@
     return std::string();
   }
   cmGeneratorTarget const* generatorTarget = this;
-  cmValue pchReuseFrom =
-    generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+  cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget();
+  bool const haveReuseTarget = reuseTarget && reuseTarget != this;
+  if (reuseTarget) {
+    generatorTarget = reuseTarget;
+  }
 
   auto const inserted =
     this->PchHeaders.insert(std::make_pair(language + config + arch, ""));
   if (inserted.second) {
     std::vector<BT<std::string>> const headers =
       this->GetPrecompileHeaders(config, language);
-    if (headers.empty() && !pchReuseFrom) {
+    if (headers.empty() && !haveReuseTarget) {
       return std::string();
     }
     std::string& filename = inserted.first->second;
 
-    if (pchReuseFrom) {
-      generatorTarget =
-        this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
-    }
-
     std::map<std::string, std::string> const languageToExtension = {
       { "C", ".h" },
       { "CXX", ".hxx" },
@@ -2857,12 +2995,13 @@
       filename = cmStrCat(filename, '/', config);
     }
 
+    // This is acceptable as its the source file, won't have a rename/hash
     filename =
       cmStrCat(filename, "/cmake_pch", arch.empty() ? "" : cmStrCat('_', arch),
                languageToExtension.at(language));
 
     std::string const filename_tmp = cmStrCat(filename, ".tmp");
-    if (!pchReuseFrom) {
+    if (!haveReuseTarget) {
       cmValue pchPrologue =
         this->Makefile->GetDefinition("CMAKE_PCH_PROLOGUE");
       cmValue pchEpilogue =
@@ -2937,11 +3076,10 @@
     std::string& filename = inserted.first->second;
 
     cmGeneratorTarget const* generatorTarget = this;
-    cmValue pchReuseFrom =
-      generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
-    if (pchReuseFrom) {
-      generatorTarget =
-        this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
+    cmGeneratorTarget const* reuseTarget = this->GetPchReuseTarget();
+    bool const haveReuseTarget = reuseTarget && reuseTarget != this;
+    if (reuseTarget) {
+      generatorTarget = reuseTarget;
     }
 
     filename =
@@ -2968,7 +3106,7 @@
     }
 
     std::string const filename_tmp = cmStrCat(filename, ".tmp");
-    if (!pchReuseFrom) {
+    if (!haveReuseTarget) {
       {
         cmGeneratedFileStream file(filename_tmp);
         file << "/* generated by CMake */\n";
@@ -2999,12 +3137,9 @@
 
     auto* pchSf = this->Makefile->GetOrCreateSource(
       pchSource, false, cmSourceFileLocationKind::Known);
-
-    filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf));
-    if (this->GetGlobalGenerator()->IsMultiConfig()) {
-      cmSystemTools::ReplaceString(
-        filename, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config);
-    }
+    pchSf->ResolveFullPath();
+    filename = cmStrCat(this->GetObjectDirectory(config), '/',
+                        this->GetObjectName(pchSf));
   }
   return inserted.first->second;
 }
@@ -3034,11 +3169,9 @@
       };
 
       cmGeneratorTarget* generatorTarget = this;
-      cmValue pchReuseFrom =
-        generatorTarget->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
-      if (pchReuseFrom) {
-        generatorTarget =
-          this->GetGlobalGenerator()->FindGeneratorTarget(*pchReuseFrom);
+      cmGeneratorTarget* reuseTarget = this->GetPchReuseTarget();
+      if (reuseTarget) {
+        generatorTarget = reuseTarget;
       }
 
       std::string const pchFileObject =
@@ -3047,8 +3180,18 @@
         pchFile = replaceExtension(pchFileObject, pchExtension);
       }
     } else {
-      pchFile = this->GetPchHeader(config, language, arch);
-      pchFile += pchExtension;
+      if (this->GetUseShortObjectNames()) {
+        auto pchSource = this->GetPchSource(config, language, arch);
+        auto* pchSf = this->Makefile->GetOrCreateSource(
+          pchSource, false, cmSourceFileLocationKind::Known);
+        pchSf->ResolveFullPath();
+        pchFile = cmStrCat(
+          this->GetSupportDirectory(), '/',
+          this->LocalGenerator->GetShortObjectFileName(*pchSf), pchExtension);
+      } else {
+        pchFile =
+          cmStrCat(this->GetPchHeader(config, language, arch), pchExtension);
+      }
     }
   }
   return inserted.first->second;
@@ -4428,7 +4571,12 @@
     }
   }
   if (out.empty()) {
-    return false;
+    // Compile output should always have a path.
+    if (kind == "COMPILE_PDB"_s) {
+      out = this->GetSupportDirectory();
+    } else {
+      return false;
+    }
   }
 
   // Convert the output path to a full path in case it is
@@ -5216,21 +5364,29 @@
       this->GetType() == cmStateEnums::MODULE_LIBRARY));
 }
 
-std::string cmGeneratorTarget::GetSupportDirectory() const
+bool cmGeneratorTarget::GetUseShortObjectNames(
+  cmStateEnums::IntermediateDirKind kind) const
+{
+  return this->LocalGenerator->UseShortObjectNames(kind);
+}
+
+std::string cmGeneratorTarget::GetSupportDirectory(
+  cmStateEnums::IntermediateDirKind kind) const
 {
   cmLocalGenerator* lg = this->GetLocalGenerator();
-  return cmStrCat(lg->GetObjectOutputRoot(), '/',
+  return cmStrCat(lg->GetObjectOutputRoot(kind), '/',
                   lg->GetTargetDirectory(this));
 }
 
-std::string cmGeneratorTarget::GetCMFSupportDirectory() const
+std::string cmGeneratorTarget::GetCMFSupportDirectory(
+  cmStateEnums::IntermediateDirKind kind) const
 {
   cmLocalGenerator* lg = this->GetLocalGenerator();
   if (!lg->AlwaysUsesCMFPaths()) {
     return cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles/",
                     lg->GetTargetDirectory(this));
   }
-  return cmStrCat(lg->GetObjectOutputRoot(), '/',
+  return cmStrCat(lg->GetObjectOutputRoot(kind), '/',
                   lg->GetTargetDirectory(this));
 }
 
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 45f7b1f..9f2349e 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -566,6 +566,7 @@
     std::string TargetPDB;
     std::string TargetCompilePDB;
     std::string ObjectDir;
+    std::string TargetSupportDir;
     std::string ObjectFileDir;
     std::string DependencyFile;
     std::string DependencyTarget;
@@ -692,6 +693,9 @@
   std::vector<BT<std::string>> GetPrecompileHeaders(
     std::string const& config, std::string const& language) const;
 
+  void MarkAsPchReused() { this->PchReused = true; }
+  cmGeneratorTarget const* GetPchReuseTarget() const;
+  cmGeneratorTarget* GetPchReuseTarget();
   std::vector<std::string> GetPchArchs(std::string const& config,
                                        std::string const& lang) const;
   std::string GetPchHeader(std::string const& config,
@@ -933,9 +937,17 @@
   /** Return whether or not the target has a DLL import library.  */
   bool HasImportLibrary(std::string const& config) const;
 
+  bool GetUseShortObjectNames(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const;
+
   /** Get a build-tree directory in which to place target support files.  */
-  std::string GetSupportDirectory() const;
-  std::string GetCMFSupportDirectory() const;
+  std::string GetSupportDirectory(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const;
+  std::string GetCMFSupportDirectory(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const;
 
   /** Return whether this target may be used to link another target.  */
   bool IsLinkable() const;
@@ -1518,6 +1530,9 @@
     std::map<cmSourceFile const*, ClassifiedFlags> SourceFlags;
   };
   mutable std::map<std::string, InfoByConfig> Configs;
+  bool PchReused = false;
+  mutable bool ComputingPchReuse = false;
+  mutable bool PchReuseCycleDetected = false;
 };
 
 class cmGeneratorTarget::TargetPropertyEntry
diff --git a/Source/cmGeneratorTarget_Sources.cxx b/Source/cmGeneratorTarget_Sources.cxx
index fa27998..ed002e4 100644
--- a/Source/cmGeneratorTarget_Sources.cxx
+++ b/Source/cmGeneratorTarget_Sources.cxx
@@ -96,10 +96,11 @@
   }
   cmake* cm = headTarget->GetLocalGenerator()->GetCMakeInstance();
   for (auto& entryCge : fileSet->CompileFileEntries()) {
-    auto tpe = cmGeneratorTarget::TargetPropertyEntry::CreateFileSet(
-      dirs, contextSensitiveDirs, std::move(entryCge), fileSet);
-    entries.Entries.emplace_back(
-      EvaluateTargetPropertyEntry(headTarget, config, "", dagChecker, *tpe));
+    auto targetPropEntry =
+      cmGeneratorTarget::TargetPropertyEntry::CreateFileSet(
+        dirs, contextSensitiveDirs, std::move(entryCge), fileSet);
+    entries.Entries.emplace_back(EvaluateTargetPropertyEntry(
+      headTarget, config, "", dagChecker, *targetPropEntry));
     EvaluatedTargetPropertyEntry const& entry = entries.Entries.back();
     for (auto const& file : entry.Values) {
       auto* sf = headTarget->Makefile->GetOrCreateSource(file);
diff --git a/Source/cmGlobVerificationManager.cxx b/Source/cmGlobVerificationManager.cxx
index 7798fc9..355ba9f 100644
--- a/Source/cmGlobVerificationManager.cxx
+++ b/Source/cmGlobVerificationManager.cxx
@@ -69,6 +69,22 @@
 
     verifyScriptFile << "if(NOT \"${NEW_GLOB}\" STREQUAL \"${OLD_GLOB}\")\n"
                      << "  message(\"-- GLOB mismatch!\")\n"
+                     << "  set(NEW_ONLY ${NEW_GLOB})\n"
+                     << "  set(OLD_ONLY ${OLD_GLOB})\n"
+                     << "  list(REMOVE_ITEM NEW_ONLY ${OLD_GLOB})\n"
+                     << "  list(REMOVE_ITEM OLD_ONLY ${NEW_GLOB})\n"
+                     << "  if(NEW_ONLY)\n"
+                     << "    message(\"The following files were added:\")\n"
+                     << "    foreach(VAR_FILE IN LISTS NEW_ONLY)\n"
+                     << "      message(\"  +${VAR_FILE}\")\n"
+                     << "    endforeach()\n"
+                     << "  endif()\n"
+                     << "  if(OLD_ONLY)\n"
+                     << "    message(\"The following files were removed:\")\n"
+                     << "    foreach(VAR_FILE IN LISTS OLD_ONLY)\n"
+                     << "      message(\"  -${VAR_FILE}\")\n"
+                     << "    endforeach()\n"
+                     << "  endif()\n"
                      << "  file(TOUCH_NOCREATE \"" << stampFile << "\")\n"
                      << "endif()\n";
   }
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index 31e8df2..adb3704 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -72,14 +72,18 @@
   std::string const& makeProgram, std::string const& projectName,
   std::string const& projectDir, std::vector<std::string> const& targetNames,
   std::string const& config, int /*jobs*/, bool verbose,
-  cmBuildOptions const& buildOptions,
-  std::vector<std::string> const& makeOptions)
+  cmBuildOptions buildOptions, std::vector<std::string> const& makeOptions)
 {
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
     makeProgram, projectName, projectDir, targetNames, config,
     cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, makeOptions);
 }
 
+std::string cmGlobalBorlandMakefileGenerator::GetShortBinaryOutputDir() const
+{
+  return "_o";
+}
+
 void cmGlobalBorlandMakefileGenerator::PrintBuildCommandAdvice(
   std::ostream& os, int jobs) const
 {
diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h
index 7fff979..a59b19f 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.h
+++ b/Source/cmGlobalBorlandMakefileGenerator.h
@@ -56,12 +56,14 @@
 
   bool IsGNUMakeJobServerAware() const override { return false; }
 
+  std::string GetShortBinaryOutputDir() const override;
+
 protected:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index bf15585..0ff2158 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -387,38 +387,15 @@
   return failed;
 }
 
-bool cmGlobalGenerator::CheckTargetsForPchCompilePdb() const
+void cmGlobalGenerator::MarkTargetsForPchReuse() const
 {
-  if (!this->GetLanguageEnabled("C") && !this->GetLanguageEnabled("CXX")) {
-    return false;
-  }
-  bool failed = false;
   for (auto const& generator : this->LocalGenerators) {
     for (auto const& target : generator->GetGeneratorTargets()) {
-      if (!target->CanCompileSources() ||
-          target->GetProperty("ghs_integrity_app").IsOn()) {
-        continue;
-      }
-
-      std::string const& reuseFrom =
-        target->GetSafeProperty("PRECOMPILE_HEADERS_REUSE_FROM");
-      std::string const& compilePdb =
-        target->GetSafeProperty("COMPILE_PDB_NAME");
-
-      if (!reuseFrom.empty() && reuseFrom != compilePdb) {
-        std::string const e = cmStrCat(
-          "PRECOMPILE_HEADERS_REUSE_FROM property is set on target (\"",
-          target->GetName(),
-          "\"). Reusable precompile headers requires the COMPILE_PDB_NAME"
-          " property to have the value \"",
-          reuseFrom, "\"\n");
-        this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
-                                               target->GetBacktrace());
-        failed = true;
+      if (auto* reuseTarget = target->GetPchReuseTarget()) {
+        reuseTarget->MarkAsPchReused();
       }
     }
   }
-  return failed;
 }
 
 bool cmGlobalGenerator::IsExportedTargetsFile(
@@ -1463,6 +1440,34 @@
     return false;
   }
 
+  if (cmValue v = this->CMakeInstance->GetCacheDefinition(
+        "CMAKE_INTERMEDIATE_DIR_STRATEGY")) {
+    if (*v == "FULL") {
+      this->IntDirStrategy = IntermediateDirStrategy::Full;
+    } else if (*v == "SHORT") {
+      this->IntDirStrategy = IntermediateDirStrategy::Short;
+    } else {
+      this->GetCMakeInstance()->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Unsupported intermediate directory strategy '", *v, '\''));
+      return false;
+    }
+  }
+  if (cmValue v = this->CMakeInstance->GetCacheDefinition(
+        "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY")) {
+    if (*v == "FULL") {
+      this->QtAutogenIntDirStrategy = IntermediateDirStrategy::Full;
+    } else if (*v == "SHORT") {
+      this->QtAutogenIntDirStrategy = IntermediateDirStrategy::Short;
+    } else {
+      this->GetCMakeInstance()->IssueMessage(
+        MessageType::FATAL_ERROR,
+        cmStrCat("Unsupported autogen intermediate directory strategy '", *v,
+                 '\''));
+      return false;
+    }
+  }
+
   // Some generators track files replaced during the Generate.
   // Start with an empty vector:
   this->FilesReplacedDuringGenerate.clear();
@@ -1550,6 +1555,8 @@
     localGen->AddHelperCommands();
   }
 
+  this->MarkTargetsForPchReuse();
+
   // Add automatically generated sources (e.g. unity build).
   // Add unity sources after computing compile features.  Unity sources do
   // not change the set of languages or features, but we need to know them
@@ -1597,10 +1604,6 @@
     return false;
   }
 
-  if (this->CheckTargetsForPchCompilePdb()) {
-    return false;
-  }
-
   for (auto const& localGen : this->LocalGenerators) {
     localGen->ComputeHomeRelativeOutputPath();
   }
@@ -2006,6 +2009,47 @@
   this->WarnedExperimental.clear();
 }
 
+bool cmGlobalGenerator::SupportsShortObjectNames() const
+{
+  return false;
+}
+
+bool cmGlobalGenerator::UseShortObjectNames(
+  cmStateEnums::IntermediateDirKind kind) const
+{
+  IntermediateDirStrategy strategy = IntermediateDirStrategy::Full;
+  switch (kind) {
+    case cmStateEnums::IntermediateDirKind::ObjectFiles:
+      strategy = this->IntDirStrategy;
+      break;
+    case cmStateEnums::IntermediateDirKind::QtAutogenMetadata:
+      strategy = this->QtAutogenIntDirStrategy;
+      break;
+    default:
+      assert(false);
+      break;
+  }
+  return this->SupportsShortObjectNames() &&
+    strategy == IntermediateDirStrategy::Short;
+}
+
+std::string cmGlobalGenerator::GetShortBinaryOutputDir() const
+{
+  return ".o";
+}
+
+std::string cmGlobalGenerator::ComputeTargetShortName(
+  std::string const& bindir, std::string const& targetName) const
+{
+  auto const& rcwbd =
+    this->LocalGenerators[0]->MaybeRelativeToTopBinDir(bindir);
+  cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512);
+  constexpr size_t HASH_TRUNCATION = 4;
+  auto dirHash = hasher.HashString(rcwbd).substr(0, HASH_TRUNCATION);
+  auto tgtHash = hasher.HashString(targetName).substr(0, HASH_TRUNCATION);
+  return cmStrCat(tgtHash, dirHash);
+}
+
 void cmGlobalGenerator::ComputeTargetObjectDirectory(
   cmGeneratorTarget* /*unused*/) const
 {
@@ -2123,7 +2167,7 @@
   std::string const& /*unused*/, std::string const& /*unused*/,
   std::string const& /*unused*/, std::vector<std::string> const& /*unused*/,
   std::string const& /*unused*/, int /*unused*/, bool /*unused*/,
-  cmBuildOptions const& /*unused*/, std::vector<std::string> const& /*unused*/)
+  cmBuildOptions /*unused*/, std::vector<std::string> const& /*unused*/)
 {
   GeneratedMakeCommand makeCommand;
   makeCommand.Add("cmGlobalGenerator::GenerateBuildCommand not implemented");
@@ -2141,7 +2185,7 @@
   int jobs, std::string const& /*unused*/, std::string const& bindir,
   std::string const& projectName, std::vector<std::string> const& targets,
   std::ostream& ostr, std::string const& makeCommandCSTR,
-  std::string const& config, cmBuildOptions const& buildOptions, bool verbose,
+  std::string const& config, cmBuildOptions buildOptions, bool verbose,
   cmDuration timeout, cmSystemTools::OutputOption outputMode,
   std::vector<std::string> const& nativeOptions)
 {
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index e7b2528..ad3d350 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -254,8 +254,8 @@
             std::string const& projectName,
             std::vector<std::string> const& targetNames, std::ostream& ostr,
             std::string const& makeProgram, std::string const& config,
-            cmBuildOptions const& buildOptions, bool verbose,
-            cmDuration timeout, cmSystemTools::OutputOption outputMode,
+            cmBuildOptions buildOptions, bool verbose, cmDuration timeout,
+            cmSystemTools::OutputOption outputMode,
             std::vector<std::string> const& nativeOptions =
               std::vector<std::string>());
 
@@ -273,7 +273,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions = std::vector<std::string>());
 
   virtual void PrintBuildCommandAdvice(std::ostream& os, int jobs) const;
@@ -629,6 +629,14 @@
     std::string const& filename) const;
   void AddCMP0068WarnTarget(std::string const& target);
 
+  virtual bool SupportsShortObjectNames() const;
+  bool UseShortObjectNames(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const;
+  virtual std::string GetShortBinaryOutputDir() const;
+  std::string ComputeTargetShortName(std::string const& bindir,
+                                     std::string const& targetName) const;
+
   virtual void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const;
 
   bool GenerateCPackPropertiesFile();
@@ -858,7 +866,7 @@
   void CheckTargetLinkLibraries() const;
   bool CheckTargetsForMissingSources() const;
   bool CheckTargetsForType() const;
-  bool CheckTargetsForPchCompilePdb() const;
+  void MarkTargetsForPchReuse() const;
 
   void CreateLocalGenerators();
 
@@ -941,6 +949,15 @@
   PerConfigModuleDatabases PerConfigModuleDbs;
   PerLanguageModuleDatabases PerLanguageModuleDbs;
 
+  enum class IntermediateDirStrategy
+  {
+    Full,
+    Short,
+  };
+  IntermediateDirStrategy IntDirStrategy = IntermediateDirStrategy::Full;
+  IntermediateDirStrategy QtAutogenIntDirStrategy =
+    IntermediateDirStrategy::Full;
+
 protected:
   float FirstTimeProgress;
   bool NeedSymbolicMark;
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
index e918268..9487153 100644
--- a/Source/cmGlobalGhsMultiGenerator.cxx
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -470,8 +470,7 @@
   std::string const& makeProgram, std::string const& projectName,
   std::string const& projectDir, std::vector<std::string> const& targetNames,
   std::string const& /*config*/, int jobs, bool verbose,
-  cmBuildOptions const& /*buildOptions*/,
-  std::vector<std::string> const& makeOptions)
+  cmBuildOptions /*buildOptions*/, std::vector<std::string> const& makeOptions)
 {
   GeneratedMakeCommand makeCommand;
 
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
index c0bc7be..e51c7ed 100644
--- a/Source/cmGlobalGhsMultiGenerator.h
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -86,7 +86,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
   void AddExtraIDETargets() override;
diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx
index a918ee0..76327ed 100644
--- a/Source/cmGlobalJOMMakefileGenerator.cxx
+++ b/Source/cmGlobalJOMMakefileGenerator.cxx
@@ -63,8 +63,7 @@
   std::string const& makeProgram, std::string const& projectName,
   std::string const& projectDir, std::vector<std::string> const& targetNames,
   std::string const& config, int jobs, bool verbose,
-  cmBuildOptions const& buildOptions,
-  std::vector<std::string> const& makeOptions)
+  cmBuildOptions buildOptions, std::vector<std::string> const& makeOptions)
 {
   std::vector<std::string> jomMakeOptions;
 
diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h
index b89c22f..0199dff 100644
--- a/Source/cmGlobalJOMMakefileGenerator.h
+++ b/Source/cmGlobalJOMMakefileGenerator.h
@@ -54,7 +54,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx
index 8209709..069a70a 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.cxx
+++ b/Source/cmGlobalNMakeMakefileGenerator.cxx
@@ -106,8 +106,7 @@
   std::string const& makeProgram, std::string const& projectName,
   std::string const& projectDir, std::vector<std::string> const& targetNames,
   std::string const& config, int /*jobs*/, bool verbose,
-  cmBuildOptions const& buildOptions,
-  std::vector<std::string> const& makeOptions)
+  cmBuildOptions buildOptions, std::vector<std::string> const& makeOptions)
 {
   std::vector<std::string> nmakeMakeOptions;
 
diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h
index 0589f2b..54de4db 100644
--- a/Source/cmGlobalNMakeMakefileGenerator.h
+++ b/Source/cmGlobalNMakeMakefileGenerator.h
@@ -61,7 +61,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index bd23906..943f149 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -1001,7 +1001,7 @@
   std::string const& makeProgram, std::string const& /*projectName*/,
   std::string const& /*projectDir*/,
   std::vector<std::string> const& targetNames, std::string const& config,
-  int jobs, bool verbose, cmBuildOptions const& /*buildOptions*/,
+  int jobs, bool verbose, cmBuildOptions /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
 {
   GeneratedMakeCommand makeCommand;
@@ -1048,6 +1048,11 @@
 
 // Private virtual overrides
 
+bool cmGlobalNinjaGenerator::SupportsShortObjectNames() const
+{
+  return true;
+}
+
 void cmGlobalNinjaGenerator::ComputeTargetObjectDirectory(
   cmGeneratorTarget* gt) const
 {
@@ -1772,8 +1777,7 @@
   this->WriteTargetRebuildManifest(os);
   this->WriteTargetClean(os);
   this->WriteTargetHelp(os);
-#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
-  // FIXME(#26668) This does not work on Windows
+#ifndef CMAKE_BOOTSTRAP
   if (this->GetCMakeInstance()
         ->GetInstrumentation()
         ->HasPreOrPostBuildHook()) {
@@ -1854,8 +1858,7 @@
   }
   reBuild.ImplicitDeps.push_back(this->CMakeCacheFile);
 
-#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
-  // FIXME(#26668) This does not work on Windows
+#ifndef CMAKE_BOOTSTRAP
   if (this->GetCMakeInstance()
         ->GetInstrumentation()
         ->HasPreOrPostBuildHook()) {
@@ -2208,8 +2211,7 @@
   }
 }
 
-#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
-// FIXME(#26668) This does not work on Windows
+#ifndef CMAKE_BOOTSTRAP
 void cmGlobalNinjaGenerator::WriteTargetInstrument(std::ostream& os)
 {
   // Write rule
@@ -2218,11 +2220,13 @@
     rule.Command = cmStrCat(
       '"', cmSystemTools::GetCTestCommand(), "\" --start-instrumentation \"",
       this->GetCMakeInstance()->GetHomeOutputDirectory(), '"');
+#  ifndef _WIN32
     /*
      * On Unix systems, Ninja will prefix the command with `/bin/sh -c`.
      * Use exec so that Ninja is the parent process of the command.
      */
     rule.Command = cmStrCat("exec ", rule.Command);
+#  endif
     rule.Description = "Collecting build metrics";
     rule.Comment = "Rule to initialize instrumentation daemon.";
     rule.Restat = "1";
@@ -2277,7 +2281,7 @@
 /*
 
 We use the following approach to support Fortran.  Each target already
-has a <target>.dir/ directory used to hold intermediate files for CMake.
+has an intermediate directory used to hold intermediate files for CMake.
 For each target, a FortranDependInfo.json file is generated by CMake with
 information about include directories, module directories, and the locations
 the per-target directories for target dependencies.
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 7e02541..8d80d13 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -201,7 +201,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
@@ -391,6 +391,7 @@
   void AddTargetAlias(std::string const& alias, cmGeneratorTarget* target,
                       std::string const& config);
 
+  bool SupportsShortObjectNames() const override;
   void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
 
   // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3
@@ -535,8 +536,7 @@
   void WriteTargetRebuildManifest(std::ostream& os);
   bool WriteTargetCleanAdditional(std::ostream& os);
   void WriteTargetClean(std::ostream& os);
-#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
-  // FIXME(#26668) This does not work on Windows
+#ifndef CMAKE_BOOTSTRAP
   void WriteTargetInstrument(std::ostream& os);
 #endif
   void WriteTargetHelp(std::ostream& os);
diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx
index 6ec64a4..fb7a4cf 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.cxx
+++ b/Source/cmGlobalUnixMakefileGenerator3.cxx
@@ -77,6 +77,11 @@
            "Generates standard UNIX makefiles." };
 }
 
+bool cmGlobalUnixMakefileGenerator3::SupportsShortObjectNames() const
+{
+  return true;
+}
+
 void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory(
   cmGeneratorTarget* gt) const
 {
@@ -531,7 +536,7 @@
   std::string const& makeProgram, std::string const& /*projectName*/,
   std::string const& /*projectDir*/,
   std::vector<std::string> const& targetNames, std::string const& /*config*/,
-  int jobs, bool verbose, cmBuildOptions const& buildOptions,
+  int jobs, bool verbose, cmBuildOptions buildOptions,
   std::vector<std::string> const& makeOptions)
 {
   GeneratedMakeCommand makeCommand;
diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h
index 75a4fdd..58755c0 100644
--- a/Source/cmGlobalUnixMakefileGenerator3.h
+++ b/Source/cmGlobalUnixMakefileGenerator3.h
@@ -172,7 +172,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
@@ -195,6 +195,7 @@
 
   bool IsIPOSupported() const override { return true; }
 
+  bool SupportsShortObjectNames() const override;
   void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
 
   std::string IncludeDirective;
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 1a21b06..70003fb 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -1050,8 +1050,7 @@
   std::string const& makeProgram, std::string const& projectName,
   std::string const& projectDir, std::vector<std::string> const& targetNames,
   std::string const& config, int jobs, bool verbose,
-  cmBuildOptions const& buildOptions,
-  std::vector<std::string> const& makeOptions)
+  cmBuildOptions buildOptions, std::vector<std::string> const& makeOptions)
 {
   std::vector<GeneratedMakeCommand> makeCommands;
   // Select the caller- or user-preferred make program, else MSBuild.
@@ -1563,6 +1562,12 @@
   return (vsVer &&
           cmSystemTools::VersionCompareGreaterEq(*vsVer, vsVer15_8_0));
 }
+
+bool cmGlobalVisualStudio10Generator::SupportsShortObjectNames() const
+{
+  return true;
+}
+
 std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const
 {
   std::string const& toolset = this->GetPlatformToolsetString();
diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h
index 5248b4d..a886be5 100644
--- a/Source/cmGlobalVisualStudio10Generator.h
+++ b/Source/cmGlobalVisualStudio10Generator.h
@@ -38,7 +38,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
@@ -184,6 +184,8 @@
   bool IsMsBuildRestoreSupported() const;
   bool IsBuildInParallelSupported() const;
 
+  bool SupportsShortObjectNames() const override;
+
 protected:
   cmGlobalVisualStudio10Generator(cmake* cm, std::string const& name);
 
diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx
index 5d4ebbd..55dcf05 100644
--- a/Source/cmGlobalVisualStudio14Generator.cxx
+++ b/Source/cmGlobalVisualStudio14Generator.cxx
@@ -57,7 +57,7 @@
   cmDocumentationEntry GetDocumentation() const override
   {
     return { std::string(vs14generatorName),
-             "Generates Visual Studio 2015 project files.  "
+             "Deprecated.  Generates Visual Studio 2015 project files.  "
              "Use -A option to specify architecture." };
   }
 
diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx
index c875be0..ee80949 100644
--- a/Source/cmGlobalVisualStudio7Generator.cxx
+++ b/Source/cmGlobalVisualStudio7Generator.cxx
@@ -217,7 +217,7 @@
   std::string const& makeProgram, std::string const& projectName,
   std::string const& /*projectDir*/,
   std::vector<std::string> const& targetNames, std::string const& config,
-  int /*jobs*/, bool /*verbose*/, cmBuildOptions const& /*buildOptions*/,
+  int /*jobs*/, bool /*verbose*/, cmBuildOptions /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
 {
   // Select the caller- or user-preferred make program, else devenv.
@@ -308,6 +308,26 @@
     this->CallVisualStudioMacro(MacroReload,
                                 GetSLNFile(this->LocalGenerators[0].get()));
   }
+
+  if (this->Version == VSVersion::VS14 &&
+      !this->CMakeInstance->GetIsInTryCompile()) {
+    std::string cmakeWarnVS14;
+    if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue(
+          "CMAKE_WARN_VS14")) {
+      this->CMakeInstance->MarkCliAsUsed("CMAKE_WARN_VS14");
+      cmakeWarnVS14 = *cached;
+    } else {
+      cmSystemTools::GetEnv("CMAKE_WARN_VS14", cmakeWarnVS14);
+    }
+    if (cmakeWarnVS14.empty() || !cmIsOff(cmakeWarnVS14)) {
+      this->CMakeInstance->IssueMessage(
+        MessageType::WARNING,
+        "The \"Visual Studio 14 2015\" generator is deprecated "
+        "and will be removed in a future version of CMake."
+        "\n"
+        "Add CMAKE_WARN_VS14=OFF to the cache to disable this warning.");
+    }
+  }
 }
 
 void cmGlobalVisualStudio7Generator::OutputSLNFile(
diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h
index c4f45b6..b2fdeb6 100644
--- a/Source/cmGlobalVisualStudio7Generator.h
+++ b/Source/cmGlobalVisualStudio7Generator.h
@@ -78,7 +78,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx
index 1036747..8061448 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.cxx
+++ b/Source/cmGlobalWatcomWMakeGenerator.cxx
@@ -67,14 +67,18 @@
   std::string const& makeProgram, std::string const& projectName,
   std::string const& projectDir, std::vector<std::string> const& targetNames,
   std::string const& config, int /*jobs*/, bool verbose,
-  cmBuildOptions const& buildOptions,
-  std::vector<std::string> const& makeOptions)
+  cmBuildOptions buildOptions, std::vector<std::string> const& makeOptions)
 {
   return this->cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
     makeProgram, projectName, projectDir, targetNames, config,
     cmake::NO_BUILD_PARALLEL_LEVEL, verbose, buildOptions, makeOptions);
 }
 
+std::string cmGlobalWatcomWMakeGenerator::GetShortBinaryOutputDir() const
+{
+  return "_o";
+}
+
 void cmGlobalWatcomWMakeGenerator::PrintBuildCommandAdvice(std::ostream& os,
                                                            int jobs) const
 {
diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h
index d0fb653..84ec7f8 100644
--- a/Source/cmGlobalWatcomWMakeGenerator.h
+++ b/Source/cmGlobalWatcomWMakeGenerator.h
@@ -55,12 +55,14 @@
 
   bool IsGNUMakeJobServerAware() const override { return false; }
 
+  std::string GetShortBinaryOutputDir() const override;
+
 protected:
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 314349a..28c47aa 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -545,7 +545,7 @@
   std::string const& makeProgram, std::string const& projectName,
   std::string const& /*projectDir*/,
   std::vector<std::string> const& targetNames, std::string const& config,
-  int jobs, bool /*verbose*/, cmBuildOptions const& /*buildOptions*/,
+  int jobs, bool /*verbose*/, cmBuildOptions /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
 {
   std::string const xcodebuild =
diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h
index a4dbde5..55c1dd3 100644
--- a/Source/cmGlobalXCodeGenerator.h
+++ b/Source/cmGlobalXCodeGenerator.h
@@ -81,7 +81,7 @@
     std::string const& makeProgram, std::string const& projectName,
     std::string const& projectDir, std::vector<std::string> const& targetNames,
     std::string const& config, int jobs, bool verbose,
-    cmBuildOptions const& buildOptions = cmBuildOptions(),
+    cmBuildOptions buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
 
diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx
index 0a39824..e9d9e15 100644
--- a/Source/cmIncludeCommand.cxx
+++ b/Source/cmIncludeCommand.cxx
@@ -10,6 +10,8 @@
 #include "cmMakefile.h"
 #include "cmMessageType.h"
 #include "cmPolicies.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
@@ -38,6 +40,13 @@
                     "include() only takes one file.");
     return false;
   }
+
+  if (status.GetMakefile().GetStateSnapshot().GetUnwindState() ==
+      cmStateEnums::UNWINDING) {
+    status.SetError("called while already in an UNWIND state");
+    return false;
+  }
+
   bool optional = false;
   bool noPolicyScope = false;
   std::string fname = args[0];
@@ -166,5 +175,22 @@
     status.SetError(m);
     return false;
   }
+
+  if (status.GetMakefile().GetStateSnapshot().GetUnwindState() ==
+      cmStateEnums::UNWINDING) {
+
+    if (status.GetMakefile().GetStateSnapshot().GetUnwindType() !=
+        cmStateEnums::CAN_UNWIND) {
+      std::string m = cmStrCat("requested file is attempting to unwind the "
+                               "stack in an invalid context:\n ",
+                               fname);
+      status.SetError(m);
+      cmSystemTools::SetFatalErrorOccurred();
+      return false;
+    }
+
+    status.SetReturnInvoked();
+  }
+
   return true;
 }
diff --git a/Source/cmInstallGetRuntimeDependenciesGenerator.cxx b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
index 9e1ecc1..0ba9f14 100644
--- a/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
+++ b/Source/cmInstallGetRuntimeDependenciesGenerator.cxx
@@ -24,7 +24,7 @@
 
 namespace {
 template <typename T, typename F>
-void WriteMultiArgument(std::ostream& os, cm::string_view const& keyword,
+void WriteMultiArgument(std::ostream& os, cm::string_view keyword,
                         std::vector<T> const& list,
                         cmScriptGeneratorIndent indent, F transform)
 {
@@ -42,7 +42,7 @@
 }
 
 void WriteFilesArgument(
-  std::ostream& os, cm::string_view const& keyword,
+  std::ostream& os, cm::string_view keyword,
   std::vector<std::unique_ptr<cmInstallRuntimeDependencySet::Item>> const&
     items,
   std::string const& config, cmScriptGeneratorIndent indent)
@@ -53,8 +53,7 @@
       -> std::string { return cmStrCat('"', i->GetItemPath(config), '"'); });
 }
 
-void WriteGenexEvaluatorArgument(std::ostream& os,
-                                 cm::string_view const& keyword,
+void WriteGenexEvaluatorArgument(std::ostream& os, cm::string_view keyword,
                                  std::vector<std::string> const& genexes,
                                  std::string const& config,
                                  cmLocalGenerator* lg,
diff --git a/Source/cmInstrumentation.cxx b/Source/cmInstrumentation.cxx
index 52461af..3065ea5 100644
--- a/Source/cmInstrumentation.cxx
+++ b/Source/cmInstrumentation.cxx
@@ -19,6 +19,8 @@
 
 #include "cmCryptoHash.h"
 #include "cmExperimental.h"
+#include "cmFileLock.h"
+#include "cmFileLockResult.h"
 #include "cmInstrumentationQuery.h"
 #include "cmJSONState.h"
 #include "cmStringAlgorithms.h"
@@ -29,6 +31,53 @@
 
 using LoadQueriesAfter = cmInstrumentation::LoadQueriesAfter;
 
+std::map<std::string, std::string> cmInstrumentation::cdashSnippetsMap = {
+  {
+    "configure",
+    "configure",
+  },
+  {
+    "generate",
+    "configure",
+  },
+  {
+    "compile",
+    "build",
+  },
+  {
+    "link",
+    "build",
+  },
+  {
+    "custom",
+    "build",
+  },
+  {
+    "build",
+    "skip",
+  },
+  {
+    "cmakeBuild",
+    "build",
+  },
+  {
+    "cmakeInstall",
+    "build",
+  },
+  {
+    "install",
+    "build",
+  },
+  {
+    "ctest",
+    "build",
+  },
+  {
+    "test",
+    "test",
+  }
+};
+
 cmInstrumentation::cmInstrumentation(std::string const& binary_dir,
                                      LoadQueriesAfter loadQueries)
 {
@@ -38,6 +87,7 @@
   this->binaryDir = binary_dir;
   this->timingDirv1 =
     cmStrCat(this->binaryDir, "/.cmake/instrumentation-", uuid, "/v1");
+  this->cdashDir = cmStrCat(this->timingDirv1, "/cdash");
   if (cm::optional<std::string> configDir =
         cmSystemTools::GetCMakeConfigDirectory()) {
     this->userTimingDirv1 =
@@ -60,7 +110,10 @@
     this->hasQuery = this->hasQuery ||
       this->ReadJSONQueries(cmStrCat(this->userTimingDirv1, "/query"));
   }
+}
 
+void cmInstrumentation::CheckCDashVariable()
+{
   std::string envVal;
   if (cmSystemTools::GetEnv("CTEST_USE_INSTRUMENTATION", envVal) &&
       !cmIsOff(envVal)) {
@@ -69,63 +122,23 @@
                                  cmExperimental::Feature::Instrumentation)
                                  .Uuid;
       if (envVal == uuid) {
+        std::set<cmInstrumentationQuery::Option> options_ = {
+          cmInstrumentationQuery::Option::CDashSubmit,
+          cmInstrumentationQuery::Option::DynamicSystemInformation
+        };
+        if (cmSystemTools::GetEnv("CTEST_USE_VERBOSE_INSTRUMENTATION",
+                                  envVal) &&
+            !cmIsOff(envVal)) {
+          options_.insert(cmInstrumentationQuery::Option::CDashVerbose);
+        }
+        for (auto const& option : options_) {
+          this->AddOption(option);
+        }
+        std::set<cmInstrumentationQuery::Hook> hooks_ = {
+          cmInstrumentationQuery::Hook::PrepareForCDash
+        };
         this->AddHook(cmInstrumentationQuery::Hook::PrepareForCDash);
-        this->AddQuery(
-          cmInstrumentationQuery::Query::DynamicSystemInformation);
-        this->cdashDir = cmStrCat(this->timingDirv1, "/cdash");
-        cmSystemTools::MakeDirectory(this->cdashDir);
-        cmSystemTools::MakeDirectory(cmStrCat(this->cdashDir, "/configure"));
-        cmSystemTools::MakeDirectory(cmStrCat(this->cdashDir, "/build"));
-        cmSystemTools::MakeDirectory(
-          cmStrCat(this->cdashDir, "/build/commands"));
-        cmSystemTools::MakeDirectory(
-          cmStrCat(this->cdashDir, "/build/targets"));
-        cmSystemTools::MakeDirectory(cmStrCat(this->cdashDir, "/test"));
-        this->cdashSnippetsMap = { {
-                                     "configure",
-                                     "configure",
-                                   },
-                                   {
-                                     "generate",
-                                     "configure",
-                                   },
-                                   {
-                                     "compile",
-                                     "build",
-                                   },
-                                   {
-                                     "link",
-                                     "build",
-                                   },
-                                   {
-                                     "custom",
-                                     "build",
-                                   },
-                                   {
-                                     "build",
-                                     "skip",
-                                   },
-                                   {
-                                     "cmakeBuild",
-                                     "build",
-                                   },
-                                   {
-                                     "cmakeInstall",
-                                     "build",
-                                   },
-                                   {
-                                     "install",
-                                     "build",
-                                   },
-                                   {
-                                     "ctest",
-                                     "build",
-                                   },
-                                   {
-                                     "test",
-                                     "test",
-                                   } };
-        this->hasQuery = true;
+        this->WriteJSONQuery(options_, hooks_, {});
       }
     }
   }
@@ -159,7 +172,7 @@
 void cmInstrumentation::ReadJSONQuery(std::string const& file)
 {
   auto query = cmInstrumentationQuery();
-  query.ReadJSON(file, this->errorMsg, this->queries, this->hooks,
+  query.ReadJSON(file, this->errorMsg, this->options, this->hooks,
                  this->callbacks);
   if (!this->errorMsg.empty()) {
     cmSystemTools::Error(cmStrCat(
@@ -174,15 +187,15 @@
 }
 
 void cmInstrumentation::WriteJSONQuery(
-  std::set<cmInstrumentationQuery::Query> const& queries_,
+  std::set<cmInstrumentationQuery::Option> const& options_,
   std::set<cmInstrumentationQuery::Hook> const& hooks_,
   std::vector<std::vector<std::string>> const& callbacks_)
 {
   Json::Value root;
   root["version"] = 1;
-  root["queries"] = Json::arrayValue;
-  for (auto const& query : queries_) {
-    root["queries"].append(cmInstrumentationQuery::QueryString[query]);
+  root["options"] = Json::arrayValue;
+  for (auto const& option : options_) {
+    root["options"].append(cmInstrumentationQuery::OptionString[option]);
   }
   root["hooks"] = Json::arrayValue;
   for (auto const& hook : hooks_) {
@@ -192,13 +205,9 @@
   for (auto const& callback : callbacks_) {
     root["callbacks"].append(cmInstrumentation::GetCommandStr(callback));
   }
-  cmsys::Directory d;
-  int n = 0;
-  if (d.Load(cmStrCat(this->timingDirv1, "/query/generated"))) {
-    n = (int)d.GetNumberOfFiles() - 2; // Don't count '.' or '..'
-  }
-  this->WriteInstrumentationJson(root, "query/generated",
-                                 cmStrCat("query-", n, ".json"));
+  this->WriteInstrumentationJson(
+    root, "query/generated",
+    cmStrCat("query-", this->writtenJsonQueries++, ".json"));
 }
 
 void cmInstrumentation::ClearGeneratedQueries()
@@ -214,9 +223,9 @@
   return this->hasQuery;
 }
 
-bool cmInstrumentation::HasQuery(cmInstrumentationQuery::Query query) const
+bool cmInstrumentation::HasOption(cmInstrumentationQuery::Option option) const
 {
-  return (this->queries.find(query) != this->queries.end());
+  return (this->options.find(option) != this->options.end());
 }
 
 bool cmInstrumentation::HasHook(cmInstrumentationQuery::Hook hook) const
@@ -281,7 +290,8 @@
   index["dataDir"] = directory;
   index["buildDir"] = this->binaryDir;
   index["version"] = 1;
-  if (this->HasQuery(cmInstrumentationQuery::Query::StaticSystemInformation)) {
+  if (this->HasOption(
+        cmInstrumentationQuery::Option::StaticSystemInformation)) {
     this->InsertStaticSystemInformation(index);
   }
   for (auto const& file : files) {
@@ -305,7 +315,7 @@
   }
 
   // Special case for CDash collation
-  if (this->HasHook(cmInstrumentationQuery::Hook::PrepareForCDash)) {
+  if (this->HasOption(cmInstrumentationQuery::Option::CDashSubmit)) {
     this->PrepareDataForCDash(directory, index_path);
   }
 
@@ -427,8 +437,8 @@
 
   // Post-Command
   this->InsertTimingData(root, steadyStart, systemStart);
-  if (this->HasQuery(
-        cmInstrumentationQuery::Query::DynamicSystemInformation)) {
+  if (this->HasOption(
+        cmInstrumentationQuery::Option::DynamicSystemInformation)) {
     this->InsertDynamicSystemInformation(root, "after");
   }
 
@@ -443,8 +453,8 @@
 
 void cmInstrumentation::GetPreTestStats()
 {
-  if (this->HasQuery(
-        cmInstrumentationQuery::Query::DynamicSystemInformation)) {
+  if (this->HasOption(
+        cmInstrumentationQuery::Option::DynamicSystemInformation)) {
     this->InsertDynamicSystemInformation(this->preTestStats, "before");
   }
 }
@@ -452,8 +462,8 @@
 int cmInstrumentation::InstrumentCommand(
   std::string command_type, std::vector<std::string> const& command,
   std::function<int()> const& callback,
-  cm::optional<std::map<std::string, std::string>> options,
-  cm::optional<std::map<std::string, std::string>> arrayOptions,
+  cm::optional<std::map<std::string, std::string>> data,
+  cm::optional<std::map<std::string, std::string>> arrayData,
   LoadQueriesAfter reloadQueriesAfterCommand)
 {
 
@@ -478,8 +488,8 @@
   auto system_start = std::chrono::system_clock::now();
   double preConfigureMemory = 0;
   double preConfigureLoad = 0;
-  if (this->HasQuery(
-        cmInstrumentationQuery::Query::DynamicSystemInformation)) {
+  if (this->HasOption(
+        cmInstrumentationQuery::Option::DynamicSystemInformation)) {
     this->InsertDynamicSystemInformation(root, "before");
   } else if (reloadQueriesAfterCommand == LoadQueriesAfter::Yes) {
     this->GetDynamicSystemInformation(preConfigureMemory, preConfigureLoad);
@@ -495,8 +505,8 @@
     if (!this->HasQuery()) {
       return ret;
     }
-    if (this->HasQuery(
-          cmInstrumentationQuery::Query::DynamicSystemInformation)) {
+    if (this->HasOption(
+          cmInstrumentationQuery::Option::DynamicSystemInformation)) {
       root["dynamicSystemInformation"] = Json::objectValue;
       root["dynamicSystemInformation"]["beforeHostMemoryUsed"] =
         preConfigureMemory;
@@ -507,14 +517,14 @@
 
   // Post-Command
   this->InsertTimingData(root, steady_start, system_start);
-  if (this->HasQuery(
-        cmInstrumentationQuery::Query::DynamicSystemInformation)) {
+  if (this->HasOption(
+        cmInstrumentationQuery::Option::DynamicSystemInformation)) {
     this->InsertDynamicSystemInformation(root, "after");
   }
 
   // Gather additional data
-  if (options.has_value()) {
-    for (auto const& item : options.value()) {
+  if (data.has_value()) {
+    for (auto const& item : data.value()) {
       if (item.first == "role" && !item.second.empty()) {
         command_type = item.second;
       } else if (!item.second.empty()) {
@@ -529,8 +539,8 @@
     root["config"] = "";
   }
 
-  if (arrayOptions.has_value()) {
-    for (auto const& item : arrayOptions.value()) {
+  if (arrayData.has_value()) {
+    for (auto const& item : arrayData.value()) {
       if (item.first == "targetLabels" && command_type != "link") {
         continue;
       }
@@ -604,27 +614,35 @@
 }
 
 /*
- * Called by ctest --start-instrumentation as part of the START_INSTRUMENTATION
- * rule when using the Ninja generator.
- * This creates a detached process which waits for the Ninja process to die
- * before running the postBuild hook. In this way, the postBuild hook triggers
- * after every ninja invocation, regardless of whether the build passed or
- * failed.
+ * Called by ctest --start-instrumentation.
+ *
+ * This creates a detached process which waits for the parent process (i.e.,
+ * the build system) to die before running the postBuild hook. In this way, the
+ * postBuild hook triggers after every invocation of the build system,
+ * regardless of whether the build passed or failed.
  */
 int cmInstrumentation::SpawnBuildDaemon()
 {
+  // Do not inherit handles from the parent process, so that the daemon is
+  // fully detached. This helps prevent deadlock between the two.
+  uv_disable_stdio_inheritance();
+
   // preBuild Hook
-  this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild);
+  if (this->LockBuildDaemon()) {
+    // Release lock before spawning the build daemon, to prevent blocking it.
+    this->lock.Release();
+    this->CollectTimingData(cmInstrumentationQuery::Hook::PreBuild);
+  }
 
   // postBuild Hook
   if (this->HasHook(cmInstrumentationQuery::Hook::PostBuild)) {
-    auto ninja_pid = uv_os_getppid();
-    if (ninja_pid) {
+    auto ppid = uv_os_getppid();
+    if (ppid) {
       std::vector<std::string> args;
       args.push_back(cmSystemTools::GetCTestCommand());
       args.push_back("--wait-and-collect-instrumentation");
       args.push_back(this->binaryDir);
-      args.push_back(std::to_string(ninja_pid));
+      args.push_back(std::to_string(ppid));
       auto builder = cmUVProcessChainBuilder().SetDetached().AddCommand(args);
       auto chain = builder.Start();
       uv_run(&chain.GetLoop(), UV_RUN_DEFAULT);
@@ -633,6 +651,16 @@
   return 0;
 }
 
+// Prevent multiple build daemons from running simultaneously
+bool cmInstrumentation::LockBuildDaemon()
+{
+  std::string const lockFile = cmStrCat(this->timingDirv1, "/.build.lock");
+  if (!cmSystemTools::FileExists(lockFile)) {
+    cmSystemTools::Touch(lockFile, true);
+  }
+  return this->lock.Lock(lockFile, 0).IsOk();
+}
+
 /*
  * Always called by ctest --wait-and-collect-instrumentation in a detached
  * process. Waits for the given PID to end before running the postBuild hook.
@@ -641,6 +669,11 @@
  */
 int cmInstrumentation::CollectTimingAfterBuild(int ppid)
 {
+  // Check if another process is already instrumenting the build.
+  // This lock will be released when the process exits at the end of the build.
+  if (!this->LockBuildDaemon()) {
+    return 0;
+  }
   std::function<int()> waitForBuild = [ppid]() -> int {
     while (0 == uv_kill(ppid, 0)) {
       cmSystemTools::Delay(100);
@@ -659,9 +692,9 @@
   this->hooks.insert(hook);
 }
 
-void cmInstrumentation::AddQuery(cmInstrumentationQuery::Query query)
+void cmInstrumentation::AddOption(cmInstrumentationQuery::Option option)
 {
-  this->queries.insert(query);
+  this->options.insert(option);
 }
 
 std::string const& cmInstrumentation::GetCDashDir()
@@ -675,6 +708,13 @@
 void cmInstrumentation::PrepareDataForCDash(std::string const& data_dir,
                                             std::string const& index_path)
 {
+  cmSystemTools::MakeDirectory(this->cdashDir);
+  cmSystemTools::MakeDirectory(cmStrCat(this->cdashDir, "/configure"));
+  cmSystemTools::MakeDirectory(cmStrCat(this->cdashDir, "/build"));
+  cmSystemTools::MakeDirectory(cmStrCat(this->cdashDir, "/build/commands"));
+  cmSystemTools::MakeDirectory(cmStrCat(this->cdashDir, "/build/targets"));
+  cmSystemTools::MakeDirectory(cmStrCat(this->cdashDir, "/test"));
+
   Json::Value root;
   std::string error_msg;
   cmJSONState parseState = cmJSONState(index_path, &root);
diff --git a/Source/cmInstrumentation.h b/Source/cmInstrumentation.h
index 46c04af..4c2629c 100644
--- a/Source/cmInstrumentation.h
+++ b/Source/cmInstrumentation.h
@@ -15,6 +15,8 @@
 #include <cm/optional>
 
 #include <cm3p/json/value.h>
+
+#include "cmFileLock.h"
 #ifndef CMAKE_BOOTSTRAP
 #  include <cmsys/SystemInformation.hxx>
 #endif
@@ -33,6 +35,7 @@
   cmInstrumentation(std::string const& binary_dir,
                     LoadQueriesAfter loadQueries = LoadQueriesAfter::Yes);
   void LoadQueries();
+  void CheckCDashVariable();
   int InstrumentCommand(
     std::string command_type, std::vector<std::string> const& command,
     std::function<int()> const& callback,
@@ -49,20 +52,21 @@
                              std::string config);
   void GetPreTestStats();
   bool HasQuery() const;
-  bool HasQuery(cmInstrumentationQuery::Query) const;
-  bool HasHook(cmInstrumentationQuery::Hook) const;
+  bool HasOption(cmInstrumentationQuery::Option option) const;
+  bool HasHook(cmInstrumentationQuery::Hook hook) const;
   bool HasPreOrPostBuildHook() const;
   bool ReadJSONQueries(std::string const& directory);
   void ReadJSONQuery(std::string const& file);
-  void WriteJSONQuery(std::set<cmInstrumentationQuery::Query> const& queries,
+  void WriteJSONQuery(std::set<cmInstrumentationQuery::Option> const& options,
                       std::set<cmInstrumentationQuery::Hook> const& hooks,
                       std::vector<std::vector<std::string>> const& callback);
   void ClearGeneratedQueries();
   int CollectTimingData(cmInstrumentationQuery::Hook hook);
   int SpawnBuildDaemon();
+  bool LockBuildDaemon();
   int CollectTimingAfterBuild(int ppid);
   void AddHook(cmInstrumentationQuery::Hook hook);
-  void AddQuery(cmInstrumentationQuery::Query query);
+  void AddOption(cmInstrumentationQuery::Option option);
   bool HasErrors() const;
   std::string const& GetCDashDir();
 
@@ -87,11 +91,11 @@
   std::string timingDirv1;
   std::string userTimingDirv1;
   std::string cdashDir;
-  std::set<cmInstrumentationQuery::Query> queries;
+  std::set<cmInstrumentationQuery::Option> options;
   std::set<cmInstrumentationQuery::Hook> hooks;
   std::vector<std::string> callbacks;
   std::vector<std::string> queryFiles;
-  std::map<std::string, std::string> cdashSnippetsMap;
+  static std::map<std::string, std::string> cdashSnippetsMap;
   Json::Value preTestStats;
   std::string errorMsg;
   bool hasQuery = false;
@@ -101,4 +105,6 @@
   std::unique_ptr<cmsys::SystemInformation> systemInformation;
   cmsys::SystemInformation& GetSystemInformation();
 #endif
+  int writtenJsonQueries = 0;
+  cmFileLock lock;
 };
diff --git a/Source/cmInstrumentationCommand.cxx b/Source/cmInstrumentationCommand.cxx
index 696968a..e9ee60b 100644
--- a/Source/cmInstrumentationCommand.cxx
+++ b/Source/cmInstrumentationCommand.cxx
@@ -35,9 +35,9 @@
   }
   version = std::atoi(versionString.c_str());
   if (version != 1) {
-    status.SetError(cmStrCat(
-      "QUERY subcommand given an unsupported ", key, " \"", versionString,
-      "\" (the only currently supported version is 1)."));
+    status.SetError(
+      cmStrCat("given an unsupported ", key, " \"", versionString,
+               "\" (the only currently supported version is 1)."));
     return false;
   }
   return true;
@@ -79,7 +79,7 @@
   {
     ArgumentParser::NonEmpty<std::string> ApiVersion;
     ArgumentParser::NonEmpty<std::string> DataVersion;
-    ArgumentParser::NonEmpty<std::vector<std::string>> Queries;
+    ArgumentParser::NonEmpty<std::vector<std::string>> Options;
     ArgumentParser::NonEmpty<std::vector<std::string>> Hooks;
     ArgumentParser::NonEmpty<std::vector<std::vector<std::string>>> Callbacks;
   };
@@ -87,7 +87,7 @@
   static auto const parser = cmArgumentParser<Arguments>{}
                                .Bind("API_VERSION"_s, &Arguments::ApiVersion)
                                .Bind("DATA_VERSION"_s, &Arguments::DataVersion)
-                               .Bind("QUERIES"_s, &Arguments::Queries)
+                               .Bind("OPTIONS"_s, &Arguments::Options)
                                .Bind("HOOKS"_s, &Arguments::Hooks)
                                .Bind("CALLBACK"_s, &Arguments::Callbacks);
 
@@ -111,17 +111,17 @@
     return false;
   }
 
-  std::set<cmInstrumentationQuery::Query> queries;
-  auto queryParser = EnumParser<cmInstrumentationQuery::Query>(
-    cmInstrumentationQuery::QueryString);
-  for (auto const& arg : arguments.Queries) {
-    cmInstrumentationQuery::Query query;
-    if (!queryParser(arg, query)) {
+  std::set<cmInstrumentationQuery::Option> options;
+  auto optionParser = EnumParser<cmInstrumentationQuery::Option>(
+    cmInstrumentationQuery::OptionString);
+  for (auto const& arg : arguments.Options) {
+    cmInstrumentationQuery::Option option;
+    if (!optionParser(arg, option)) {
       status.SetError(
-        cmStrCat("given invalid argument to QUERIES \"", arg, '"'));
+        cmStrCat("given invalid argument to OPTIONS \"", arg, '"'));
       return false;
     }
-    queries.insert(query);
+    options.insert(option);
   }
 
   std::set<cmInstrumentationQuery::Hook> hooks;
@@ -140,7 +140,7 @@
   status.GetMakefile()
     .GetCMakeInstance()
     ->GetInstrumentation()
-    ->WriteJSONQuery(queries, hooks, arguments.Callbacks);
+    ->WriteJSONQuery(options, hooks, arguments.Callbacks);
 
   return true;
 }
diff --git a/Source/cmInstrumentationQuery.cxx b/Source/cmInstrumentationQuery.cxx
index 7bc27be..d9e6f7e 100644
--- a/Source/cmInstrumentationQuery.cxx
+++ b/Source/cmInstrumentationQuery.cxx
@@ -15,8 +15,9 @@
 #include "cmJSONHelpers.h"
 #include "cmStringAlgorithms.h"
 
-std::vector<std::string> const cmInstrumentationQuery::QueryString{
-  "staticSystemInformation", "dynamicSystemInformation"
+std::vector<std::string> const cmInstrumentationQuery::OptionString{
+  "staticSystemInformation", "dynamicSystemInformation", "cdashSubmit",
+  "cdashVerbose"
 };
 std::vector<std::string> const cmInstrumentationQuery::HookString{
   "postGenerate",  "preBuild",        "postBuild",
@@ -64,11 +65,11 @@
     return false;
   };
 }
-static auto const QueryHelper = EnumHelper<cmInstrumentationQuery::Query>(
-  cmInstrumentationQuery::QueryString, "query");
+static auto const OptionHelper = EnumHelper<cmInstrumentationQuery::Option>(
+  cmInstrumentationQuery::OptionString, "option");
 static auto const QueryListHelper =
-  JSONHelperBuilder::Vector<cmInstrumentationQuery::Query>(
-    ErrorMessages::InvalidArray, QueryHelper);
+  JSONHelperBuilder::Vector<cmInstrumentationQuery::Option>(
+    ErrorMessages::InvalidArray, OptionHelper);
 static auto const HookHelper = EnumHelper<cmInstrumentationQuery::Hook>(
   cmInstrumentationQuery::HookString, "hook");
 static auto const HookListHelper =
@@ -85,13 +86,13 @@
   JSONHelperBuilder::Object<QueryRoot>(ErrorMessages::InvalidRootQueryObject,
                                        false)
     .Bind("version"_s, &QueryRoot::version, VersionHelper, true)
-    .Bind("queries"_s, &QueryRoot::queries, QueryListHelper, false)
+    .Bind("options"_s, &QueryRoot::options, QueryListHelper, false)
     .Bind("hooks"_s, &QueryRoot::hooks, HookListHelper, false)
     .Bind("callbacks"_s, &QueryRoot::callbacks, CallbackListHelper, false);
 
 bool cmInstrumentationQuery::ReadJSON(std::string const& filename,
                                       std::string& errorMessage,
-                                      std::set<Query>& queries,
+                                      std::set<Option>& options,
                                       std::set<Hook>& hooks,
                                       std::vector<std::string>& callbacks)
 {
@@ -105,8 +106,8 @@
     errorMessage = this->parseState.GetErrorMessage(true);
     return false;
   }
-  std::move(this->queryRoot.queries.begin(), this->queryRoot.queries.end(),
-            std::inserter(queries, queries.end()));
+  std::move(this->queryRoot.options.begin(), this->queryRoot.options.end(),
+            std::inserter(options, options.end()));
   std::move(this->queryRoot.hooks.begin(), this->queryRoot.hooks.end(),
             std::inserter(hooks, hooks.end()));
   std::move(this->queryRoot.callbacks.begin(), this->queryRoot.callbacks.end(),
diff --git a/Source/cmInstrumentationQuery.h b/Source/cmInstrumentationQuery.h
index 3d5fdac..70bb5ce 100644
--- a/Source/cmInstrumentationQuery.h
+++ b/Source/cmInstrumentationQuery.h
@@ -12,12 +12,14 @@
 {
 
 public:
-  enum Query
+  enum Option
   {
     StaticSystemInformation,
-    DynamicSystemInformation
+    DynamicSystemInformation,
+    CDashSubmit,
+    CDashVerbose
   };
-  static std::vector<std::string> const QueryString;
+  static std::vector<std::string> const OptionString;
 
   enum Hook
   {
@@ -35,7 +37,7 @@
 
   struct QueryJSONRoot
   {
-    std::vector<cmInstrumentationQuery::Query> queries;
+    std::vector<cmInstrumentationQuery::Option> options;
     std::vector<cmInstrumentationQuery::Hook> hooks;
     std::vector<std::string> callbacks;
     int version;
@@ -43,7 +45,7 @@
 
   cmInstrumentationQuery() = default;
   bool ReadJSON(std::string const& file, std::string& errorMessage,
-                std::set<Query>& queries, std::set<Hook>& hooks,
+                std::set<Option>& options, std::set<Hook>& hooks,
                 std::vector<std::string>& callbacks);
   QueryJSONRoot queryRoot;
   cmJSONState parseState;
diff --git a/Source/cmJSONHelpers.h b/Source/cmJSONHelpers.h
index a5f71dd..ab96c64 100644
--- a/Source/cmJSONHelpers.h
+++ b/Source/cmJSONHelpers.h
@@ -96,7 +96,7 @@
     }
 
     template <typename U, typename M, typename F>
-    Object& Bind(cm::string_view const& name, M U::*member, F func,
+    Object& Bind(cm::string_view name, M U::*member, F func,
                  bool required = true)
     {
       return this->BindPrivate(
@@ -106,7 +106,7 @@
         required);
     }
     template <typename M, typename F>
-    Object& Bind(cm::string_view const& name, std::nullptr_t, F func,
+    Object& Bind(cm::string_view name, std::nullptr_t, F func,
                  bool required = true)
     {
       return this->BindPrivate(
@@ -119,7 +119,7 @@
         required);
     }
     template <typename F>
-    Object& Bind(cm::string_view const& name, F func, bool required = true)
+    Object& Bind(cm::string_view name, F func, bool required = true)
     {
       return this->BindPrivate(name, MemberFunction(func), required);
     }
@@ -197,7 +197,7 @@
     JsonErrors::ObjectErrorGenerator Error;
     bool AllowExtra;
 
-    Object& BindPrivate(cm::string_view const& name, MemberFunction&& func,
+    Object& BindPrivate(cm::string_view name, MemberFunction&& func,
                         bool required)
     {
       this->Members.emplace_back(name, std::move(func), required);
diff --git a/Source/cmList.cxx b/Source/cmList.cxx
index 77b7916..9087457 100644
--- a/Source/cmList.cxx
+++ b/Source/cmList.cxx
@@ -134,7 +134,7 @@
   }
 
 public:
-  StringSorter(cmList::SortConfiguration const& config)
+  StringSorter(cmList::SortConfiguration config)
     : Filters{ this->GetCompareFilter(config.Compare),
                this->GetCaseFilter(config.Case) }
     , SortMethod(this->GetComparisonFunction(config.Compare))
@@ -175,7 +175,7 @@
 
 cmList::SortConfiguration::SortConfiguration() = default;
 
-cmList& cmList::sort(SortConfiguration const& cfg)
+cmList& cmList::sort(SortConfiguration cfg)
 {
   SortConfiguration config{ cfg };
 
@@ -910,7 +910,7 @@
   // compute all indexes
   std::vector<size_type> idx(indexes.size());
   std::transform(indexes.cbegin(), indexes.cend(), idx.begin(),
-                 [this](index_type const& index) -> size_type {
+                 [this](index_type index) -> size_type {
                    return this->ComputeIndex(index);
                  });
 
diff --git a/Source/cmList.h b/Source/cmList.h
index c355910..41b401b 100644
--- a/Source/cmList.h
+++ b/Source/cmList.h
@@ -863,7 +863,7 @@
     {
     }
   };
-  cmList& sort(SortConfiguration const& config = SortConfiguration{});
+  cmList& sort(SortConfiguration config = SortConfiguration{});
 
   // exception raised on error during transform operations
   class transform_error : public std::runtime_error
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index 9aa5b20..4de723e 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -456,8 +456,9 @@
   return !parseError;
 }
 
-#include "cmConstStack.tcc"
-template class cmConstStack<cmListFileContext, cmListFileBacktrace>;
+#include "cmStack.tcc"
+template class cmStack<cmListFileContext const, cmListFileBacktrace,
+                       cmStackType::Const>;
 
 std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
 {
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
index ad78c51..fe2ee08 100644
--- a/Source/cmListFileCache.h
+++ b/Source/cmListFileCache.h
@@ -12,8 +12,8 @@
 
 #include <cm/optional>
 
-#include "cmConstStack.h"
 #include "cmList.h"
+#include "cmStack.h"
 #include "cmSystemTools.h"
 
 /** \class cmListFileCache
@@ -169,11 +169,12 @@
 class cmListFileBacktrace
   : public cmConstStack<cmListFileContext, cmListFileBacktrace>
 {
-  using cmConstStack::cmConstStack;
-  friend class cmConstStack<cmListFileContext, cmListFileBacktrace>;
+  using cmStack::cmStack;
+  friend cmListFileBacktrace::Base;
 };
 #ifndef cmListFileCache_cxx
-extern template class cmConstStack<cmListFileContext, cmListFileBacktrace>;
+extern template class cmStack<cmListFileContext const, cmListFileBacktrace,
+                              cmStackType::Const>;
 #endif
 
 // Wrap type T as a value with a backtrace.  For purposes of
diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx
index badb3ee..3a8453e 100644
--- a/Source/cmLocalCommonGenerator.cxx
+++ b/Source/cmLocalCommonGenerator.cxx
@@ -89,7 +89,7 @@
   return flags;
 }
 
-std::string cmLocalCommonGenerator::GetTargetDirectory(
+std::string cmLocalCommonGenerator::ComputeLongTargetDirectory(
   cmGeneratorTarget const* target) const
 {
   std::string dir = target->GetName();
@@ -101,6 +101,15 @@
   return dir;
 }
 
+std::string cmLocalCommonGenerator::GetTargetDirectory(
+  cmGeneratorTarget const* target) const
+{
+  if (target->GetUseShortObjectNames()) {
+    return this->ComputeShortTargetDirectory(target);
+  }
+  return this->ComputeLongTargetDirectory(target);
+}
+
 void cmLocalCommonGenerator::ComputeObjectFilenames(
   std::map<cmSourceFile const*, std::string>& mapping,
   cmGeneratorTarget const* gt)
diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h
index bcc866c..7c63c19 100644
--- a/Source/cmLocalCommonGenerator.h
+++ b/Source/cmLocalCommonGenerator.h
@@ -34,6 +34,7 @@
   std::string GetTargetFortranFlags(cmGeneratorTarget const* target,
                                     std::string const& config) override;
 
+  std::string ComputeLongTargetDirectory(cmGeneratorTarget const* gt) const;
   std::string GetTargetDirectory(
     cmGeneratorTarget const* target) const override;
 
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 2638af1..78b0d08 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -78,6 +78,8 @@
   "CMAKE_SHARED_LIBRARY_SONAME_${LANG}_FLAG",
   "CMAKE_${LANG}_ARCHIVE",
   "CMAKE_AR",
+  "CMAKE_SOURCE_DIR",
+  "CMAKE_BINARY_DIR",
   "CMAKE_CURRENT_SOURCE_DIR",
   "CMAKE_CURRENT_BINARY_DIR",
   "CMAKE_RANLIB",
@@ -2779,8 +2781,8 @@
           continue;
         }
 
-        cmValue ReuseFrom =
-          target->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM");
+        auto* reuseTarget = target->GetPchReuseTarget();
+        bool const haveReuseTarget = reuseTarget && reuseTarget != target;
 
         auto* pch_sf = this->Makefile->GetOrCreateSource(
           pchSource, false, cmSourceFileLocationKind::Known);
@@ -2789,7 +2791,7 @@
         pch_sf->SetProperty("CXX_SCAN_FOR_MODULES", "0");
 
         if (!this->GetGlobalGenerator()->IsXcode()) {
-          if (!ReuseFrom) {
+          if (!haveReuseTarget) {
             target->AddSource(pchSource, true);
           }
 
@@ -2797,14 +2799,11 @@
 
           // Exclude the pch files from linking
           if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
-            if (!ReuseFrom) {
+            if (!haveReuseTarget) {
               pch_sf->AppendProperty(
                 "OBJECT_OUTPUTS",
                 cmStrCat("$<$<CONFIG:", config, ">:", pchFile, '>'));
             } else {
-              auto* reuseTarget =
-                this->GlobalGenerator->FindGeneratorTarget(*ReuseFrom);
-
               if (this->Makefile->IsOn("CMAKE_PCH_COPY_COMPILE_PDB")) {
 
                 std::string const compilerId =
@@ -2838,23 +2837,12 @@
                     langFlags.find("-Zi") != std::string::npos;
                 }
 
-                // MSVC 2008 is producing both .pdb and .idb files with /Zi.
-                bool msvc2008OrLess =
-                  cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
-                                                compilerVersion, "16.0") &&
-                  compilerId == "MSVC";
-                // but not when used via toolset -Tv90
-                if (this->Makefile->GetSafeDefinition(
-                      "CMAKE_VS_PLATFORM_TOOLSET") == "v90") {
-                  msvc2008OrLess = false;
-                }
-
-                if (editAndContinueDebugInfo || msvc2008OrLess) {
-                  this->CopyPchCompilePdb(config, lang, target, *ReuseFrom,
-                                          reuseTarget, { ".pdb", ".idb" });
+                if (editAndContinueDebugInfo) {
+                  this->CopyPchCompilePdb(config, lang, target, reuseTarget,
+                                          { ".pdb", ".idb" });
                 } else if (programDatabaseDebugInfo) {
-                  this->CopyPchCompilePdb(config, lang, target, *ReuseFrom,
-                                          reuseTarget, { ".pdb" });
+                  this->CopyPchCompilePdb(config, lang, target, reuseTarget,
+                                          { ".pdb" });
                 }
               }
 
@@ -2906,18 +2894,11 @@
 
 void cmLocalGenerator::CopyPchCompilePdb(
   std::string const& config, std::string const& language,
-  cmGeneratorTarget* target, std::string const& ReuseFrom,
-  cmGeneratorTarget* reuseTarget, std::vector<std::string> const& extensions)
+  cmGeneratorTarget* target, cmGeneratorTarget* reuseTarget,
+  std::vector<std::string> const& extensions)
 {
-  std::string const pdb_prefix =
-    this->GetGlobalGenerator()->IsMultiConfig() ? cmStrCat(config, '/') : "";
-
-  std::string const target_compile_pdb_dir =
-    cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/',
-             target->GetName(), ".dir/");
-
-  std::string const copy_script =
-    cmStrCat(target_compile_pdb_dir, "copy_idb_pdb_", config, ".cmake");
+  std::string const copy_script = cmStrCat(target->GetSupportDirectory(),
+                                           "/copy_idb_pdb_", config, ".cmake");
   cmGeneratedFileStream file(copy_script);
 
   file << "# CMake generated file\n";
@@ -2926,28 +2907,36 @@
        << "# by mspdbsrv. The foreach retry loop is needed to make sure\n"
        << "# the pdb file is ready to be copied.\n\n";
 
+  auto configGenex = [&](cm::string_view expr) -> std::string {
+    if (this->GetGlobalGenerator()->IsMultiConfig()) {
+      return cmStrCat("$<$<CONFIG:", config, ">:", expr, '>');
+    }
+    return std::string(expr);
+  };
+
+  std::vector<std::string> outputs;
+  auto replaceExtension = [](std::string const& path,
+                             std::string const& ext) -> std::string {
+    auto const dir = cmSystemTools::GetFilenamePath(path);
+    auto const base = cmSystemTools::GetFilenameWithoutLastExtension(path);
+    if (dir.empty()) {
+      return cmStrCat(base, ext);
+    }
+    return cmStrCat(dir, '/', base, ext);
+  };
   for (auto const& extension : extensions) {
     std::string const from_file =
-      cmStrCat(reuseTarget->GetLocalGenerator()->GetCurrentBinaryDirectory(),
-               '/', ReuseFrom, ".dir/${PDB_PREFIX}", ReuseFrom, extension);
-
-    std::string const to_dir =
-      cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/',
-               target->GetName(), ".dir/${PDB_PREFIX}");
-
-    std::string const to_file = cmStrCat(to_dir, ReuseFrom, extension);
-
-    std::string dest_file = to_file;
-
-    std::string const& prefix = target->GetSafeProperty("PREFIX");
-    if (!prefix.empty()) {
-      dest_file = cmStrCat(to_dir, prefix, ReuseFrom, extension);
-    }
+      replaceExtension(reuseTarget->GetCompilePDBPath(config), extension);
+    std::string const to_dir = target->GetCompilePDBDirectory(config);
+    std::string const to_file =
+      replaceExtension(reuseTarget->GetCompilePDBName(config), extension);
+    std::string const dest_file = cmStrCat(to_dir, '/', to_file);
 
     file << "foreach(retry RANGE 1 30)\n";
     file << "  if (EXISTS \"" << from_file << "\" AND (NOT EXISTS \""
-         << dest_file << "\" OR NOT \"" << dest_file << "  \" IS_NEWER_THAN \""
+         << dest_file << "\" OR NOT \"" << dest_file << "\" IS_NEWER_THAN \""
          << from_file << "\"))\n";
+    file << "    file(MAKE_DIRECTORY \"" << to_dir << "\")\n";
     file << "    execute_process(COMMAND ${CMAKE_COMMAND} -E copy";
     file << " \"" << from_file << "\""
          << " \"" << to_dir << "\" RESULT_VARIABLE result "
@@ -2956,10 +2945,6 @@
          << "      execute_process(COMMAND ${CMAKE_COMMAND}"
          << " -E sleep 1)\n"
          << "    else()\n";
-    if (!prefix.empty()) {
-      file << "  file(REMOVE \"" << dest_file << "\")\n";
-      file << "  file(RENAME \"" << to_file << "\" \"" << dest_file << "\")\n";
-    }
     file << "      break()\n"
          << "    endif()\n";
     file << "  elseif(NOT EXISTS \"" << from_file << "\")\n"
@@ -2967,31 +2952,24 @@
          << " -E sleep 1)\n"
          << "  endif()\n";
     file << "endforeach()\n";
+    outputs.push_back(configGenex(dest_file));
   }
 
-  auto configGenex = [&](cm::string_view expr) -> std::string {
-    if (this->GetGlobalGenerator()->IsMultiConfig()) {
-      return cmStrCat("$<$<CONFIG:", config, ">:", expr, '>');
-    }
-    return std::string(expr);
-  };
+  cmCustomCommandLines commandLines =
+    cmMakeSingleCommandLine({ configGenex(cmSystemTools::GetCMakeCommand()),
+                              configGenex("-P"), configGenex(copy_script) });
 
-  cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
-    { configGenex(cmSystemTools::GetCMakeCommand()),
-      configGenex(cmStrCat("-DPDB_PREFIX=", pdb_prefix)), configGenex("-P"),
-      configGenex(copy_script) });
-
-  char const* no_message = "";
-
-  std::vector<std::string> outputs;
-  outputs.push_back(configGenex(
-    cmStrCat(target_compile_pdb_dir, pdb_prefix, ReuseFrom, ".pdb")));
+  auto const comment =
+    cmStrCat("Copying PDB for PCH reuse from ", reuseTarget->GetName(),
+             " for ", target->GetName());
+  ;
 
   auto cc = cm::make_unique<cmCustomCommand>();
   cc->SetCommandLines(commandLines);
-  cc->SetComment(no_message);
+  cc->SetComment(comment.c_str());
   cc->SetStdPipesUTF8(true);
-  cc->AppendDepends({ reuseTarget->GetPchFile(config, language) });
+  cc->AppendDepends(
+    { reuseTarget->GetPchFile(config, language), copy_script });
 
   if (this->GetGlobalGenerator()->IsVisualStudio()) {
     cc->SetByproducts(outputs);
@@ -3007,9 +2985,6 @@
       target->AddSource(copy_rule->ResolveFullPath());
     }
   }
-
-  target->Target->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
-                              target_compile_pdb_dir);
 }
 
 cm::optional<std::string> cmLocalGenerator::GetMSVCDebugFormatName(
@@ -4201,9 +4176,8 @@
 }
 }
 
-std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
-  cmSourceFile const& source, std::string const& dir_max,
-  bool* hasSourceExtension, char const* customOutputExtension)
+std::string cmLocalGenerator::GetRelativeSourceFileName(
+  cmSourceFile const& source) const
 {
   // Construct the object file name using the full path to the source
   // file which is its only unique identification.
@@ -4236,7 +4210,17 @@
   } else {
     objectName = relFromSource;
   }
+  return objectName;
+}
 
+std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
+  cmSourceFile const& source, std::string const& dir_max,
+  bool* hasSourceExtension, char const* customOutputExtension)
+{
+
+  // This can return an absolute path in the case where source is
+  // not relative to the current source or binary directoreis
+  std::string objectName = this->GetRelativeSourceFileName(source);
   // if it is still a full path check for the try compile case
   // try compile never have in source sources, and should not
   // have conflicting source file names in the same target
@@ -4245,13 +4229,21 @@
       objectName = cmSystemTools::GetFilenameName(source.GetFullPath());
     }
   }
+  bool const isPchObject = objectName.find("cmake_pch") != std::string::npos;
+
+  // Short object path policy selected, use as little info as necessary to
+  // select an object name
+  bool keptSourceExtension = true;
+  if (this->UseShortObjectNames()) {
+    objectName = this->GetShortObjectFileName(source);
+    keptSourceExtension = false;
+  }
 
   // Ensure that for the CMakeFiles/<target>.dir/generated_source_file
   // we don't end up having:
   // CMakeFiles/<target>.dir/CMakeFiles/<target>.dir/generated_source_file.obj
   cmValue unitySourceFile = source.GetProperty("UNITY_SOURCE_FILE");
   cmValue pchExtension = source.GetProperty("PCH_EXTENSION");
-  bool const isPchObject = objectName.find("cmake_pch") != std::string::npos;
   if (unitySourceFile || pchExtension || isPchObject) {
     if (pchExtension) {
       customOutputExtension = pchExtension->c_str();
@@ -4265,7 +4257,6 @@
 
   // Replace the original source file extension with the object file
   // extension.
-  bool keptSourceExtension = true;
   if (!source.GetPropertyAsBool("KEEP_EXTENSION")) {
     // Decide whether this language wants to replace the source
     // extension with the object extension.
@@ -4285,6 +4276,10 @@
       }
     }
 
+    // Strip source file extension when shortening object file paths
+    if (this->UseShortObjectNames()) {
+      objectName = cmSystemTools::GetFilenameWithoutExtension(objectName);
+    }
     // Store the new extension.
     if (customOutputExtension) {
       objectName += customOutputExtension;
@@ -4300,8 +4295,19 @@
   return this->CreateSafeUniqueObjectFileName(objectName, dir_max);
 }
 
-std::string cmLocalGenerator::GetObjectOutputRoot() const
+bool cmLocalGenerator::UseShortObjectNames(
+  cmStateEnums::IntermediateDirKind kind) const
 {
+  return this->GlobalGenerator->UseShortObjectNames(kind);
+}
+
+std::string cmLocalGenerator::GetObjectOutputRoot(
+  cmStateEnums::IntermediateDirKind kind) const
+{
+  if (this->UseShortObjectNames(kind)) {
+    return cmStrCat(this->GetCurrentBinaryDirectory(), '/',
+                    this->GlobalGenerator->GetShortBinaryOutputDir());
+  }
   return cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles");
 }
 
@@ -4310,6 +4316,26 @@
   return true;
 }
 
+std::string cmLocalGenerator::GetShortObjectFileName(
+  cmSourceFile const& source) const
+{
+  std::string objectName = this->GetRelativeSourceFileName(source);
+  std::string objectFileName =
+    cmSystemTools::GetFilenameName(source.GetFullPath());
+  cmCryptoHash objNameHasher(cmCryptoHash::AlgoSHA3_512);
+  std::string terseObjectName =
+    objNameHasher.HashString(objectName).substr(0, 8);
+  return terseObjectName;
+}
+
+std::string cmLocalGenerator::ComputeShortTargetDirectory(
+  cmGeneratorTarget const* target) const
+{
+  auto const& tgtName = target->GetName();
+  return this->GetGlobalGenerator()->ComputeTargetShortName(
+    this->GetCurrentBinaryDirectory(), tgtName);
+}
+
 std::string cmLocalGenerator::GetSourceFileLanguage(cmSourceFile const& source)
 {
   return source.GetLanguage();
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 1042111..4fa48fb 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -24,6 +24,7 @@
 #include "cmOutputConverter.h"
 #include "cmPolicies.h"
 #include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
 #include "cmValue.h"
 
 class cmCompiledGeneratorExpression;
@@ -290,6 +291,7 @@
 
   /** Called from command-line hook to update dependencies.  */
   virtual bool UpdateDependencies(std::string const& /* tgtInfo */,
+                                  std::string const& /* targetName */,
                                   bool /*verbose*/, bool /*color*/)
   {
     return true;
@@ -438,8 +440,16 @@
   std::string const& GetCurrentBinaryDirectory() const;
   std::string const& GetCurrentSourceDirectory() const;
 
-  virtual std::string GetObjectOutputRoot() const;
+  bool UseShortObjectNames(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const;
+  virtual std::string GetObjectOutputRoot(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const;
   virtual bool AlwaysUsesCMFPaths() const;
+  virtual std::string GetShortObjectFileName(cmSourceFile const& source) const;
+  virtual std::string ComputeShortTargetDirectory(
+    cmGeneratorTarget const* gt) const;
 
   /**
    * Generate a macOS application bundle Info.plist file.
@@ -457,6 +467,8 @@
   /** Construct a comment for a custom command.  */
   std::string ConstructComment(cmCustomCommandGenerator const& ccg,
                                char const* default_comment = "") const;
+  // Computes relative path to source respective to source or binary dir.
+  std::string GetRelativeSourceFileName(cmSourceFile const& source) const;
   // Compute object file names.
   std::string GetObjectFileNameWithoutTarget(
     cmSourceFile const& source, std::string const& dir_max,
@@ -640,7 +652,6 @@
   void CopyPchCompilePdb(std::string const& config,
                          std::string const& language,
                          cmGeneratorTarget* target,
-                         std::string const& ReuseFrom,
                          cmGeneratorTarget* reuseTarget,
                          std::vector<std::string> const& extensions);
 
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index b0c4051..a1b9c34 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -163,6 +163,16 @@
   }
 }
 
+std::string cmLocalNinjaGenerator::GetObjectOutputRoot(
+  cmStateEnums::IntermediateDirKind kind) const
+{
+  if (this->UseShortObjectNames(kind)) {
+    return cmStrCat(this->GetBinaryDirectory(), '/',
+                    this->GetGlobalGenerator()->GetShortBinaryOutputDir());
+  }
+  return cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles");
+}
+
 // Non-virtual public methods.
 
 cmGlobalNinjaGenerator const* cmLocalNinjaGenerator::GetGlobalNinjaGenerator()
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index 95f5c89..763ec64 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -15,6 +15,7 @@
 #include "cmLocalCommonGenerator.h"
 #include "cmNinjaTypes.h"
 #include "cmOutputConverter.h"
+#include "cmStateTypes.h"
 
 class cmCustomCommand;
 class cmCustomCommandGenerator;
@@ -62,6 +63,9 @@
   {
     return this->HomeRelativeOutputPath;
   }
+  std::string GetObjectOutputRoot(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const override;
 
   std::string BuildCommandLine(
     std::vector<std::string> const& cmdLines, std::string const& outputConfig,
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 609f46e..c3d6ac7 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -74,21 +74,22 @@
   return ext;
 }
 
-#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
+#ifndef CMAKE_BOOTSTRAP
 // Helper function to add the Start Instrumentation command
 void addInstrumentationCommand(cmInstrumentation* instrumentation,
                                std::vector<std::string>& commands)
 {
-  // FIXME(#26668) This does not work on Windows
   if (instrumentation->HasPreOrPostBuildHook()) {
     std::string instrumentationCommand =
       "$(CTEST_COMMAND) --start-instrumentation $(CMAKE_BINARY_DIR)";
+#  ifndef _WIN32
     /*
      * On Unix systems, Make will prefix the command with `/bin/sh -c`.
      * Use exec so that Make is the parent process of the command.
      * Add a `;` to convince BSD make to not optimize out the shell.
      */
     instrumentationCommand = cmStrCat("exec ", instrumentationCommand, " ;");
+#  endif
     commands.push_back(instrumentationCommand);
   }
 }
@@ -200,6 +201,16 @@
   this->WriteDirectoryInformationFile();
 }
 
+std::string cmLocalUnixMakefileGenerator3::GetObjectOutputRoot(
+  cmStateEnums::IntermediateDirKind kind) const
+{
+  if (this->UseShortObjectNames(kind)) {
+    return cmStrCat(this->GetCurrentBinaryDirectory(), '/',
+                    this->GetGlobalGenerator()->GetShortBinaryOutputDir());
+  }
+  return cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles");
+}
+
 void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath()
 {
   // Compute the path to use when referencing the current output
@@ -687,11 +698,12 @@
                     "CMAKE_COMMAND = "
                  << cmakeShellCommand << "\n";
 
-#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
-  // FIXME(#26668) This does not work on Windows
+#ifndef CMAKE_BOOTSTRAP
   if (this->GetCMakeInstance()
         ->GetInstrumentation()
-        ->HasPreOrPostBuildHook()) {
+        ->HasPreOrPostBuildHook() &&
+      // FIXME(#27079): This does not work for MSYS Makefiles.
+      this->GlobalGenerator->GetName() != "MSYS Makefiles") {
     std::string ctestShellCommand =
       getShellCommand(cmSystemTools::GetCTestCommand());
     makefileStream << "# The CTest executable.\n"
@@ -849,9 +861,12 @@
 
     std::vector<std::string> no_depends;
     commands.push_back(std::move(runRule));
-#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
-    addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(),
-                              commands);
+#ifndef CMAKE_BOOTSTRAP
+    // FIXME(#27079): This does not work for MSYS Makefiles.
+    if (this->GlobalGenerator->GetName() != "MSYS Makefiles") {
+      addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(),
+                                commands);
+    }
 #endif
     if (!this->IsRootMakefile()) {
       this->CreateCDCommand(commands, this->GetBinaryDirectory(),
@@ -1031,6 +1046,14 @@
       if (cmNonempty(val)) {
         // Expand rule variables referenced in the given launcher command.
         cmRulePlaceholderExpander::RuleVariables vars;
+        std::string targetSupportDir =
+          target->GetGlobalGenerator()->ConvertToOutputPath(
+            target->GetCMFSupportDirectory());
+        targetSupportDir = target->GetLocalGenerator()->ConvertToOutputFormat(
+          target->GetLocalGenerator()->MaybeRelativeToTopBinDir(
+            targetSupportDir),
+          cmOutputConverter::SHELL);
+        vars.TargetSupportDir = targetSupportDir.c_str();
         vars.CMTargetName = target->GetName().c_str();
         vars.CMTargetType =
           cmState::GetTargetTypeName(target->GetType()).c_str();
@@ -1363,7 +1386,8 @@
 }
 
 bool cmLocalUnixMakefileGenerator3::UpdateDependencies(
-  std::string const& tgtInfo, bool verbose, bool color)
+  std::string const& tgtInfo, std::string const& targetName, bool verbose,
+  bool color)
 {
   // read in the target info file
   if (!this->Makefile->ReadListFile(tgtInfo) ||
@@ -1460,8 +1484,6 @@
     if (needRescanDependInfo || needRescanDirInfo || needRescanDependencies) {
       // The dependencies must be regenerated.
       if (verbose) {
-        std::string targetName = cmSystemTools::GetFilenameName(targetDir);
-        targetName = targetName.substr(0, targetName.length() - 4);
         std::string message =
           cmStrCat("Scanning dependencies of target ", targetName);
         echoColor(message);
@@ -1495,10 +1517,6 @@
                       : std::function<bool(std::string const&)>())) {
       // regenerate dependencies files
       if (verbose) {
-        std::string targetName = cmCMakePath(targetDir)
-                                   .GetFileName()
-                                   .RemoveExtension()
-                                   .GenericString();
         auto message =
           cmStrCat("Consolidate compiler generated dependencies of target ",
                    targetName);
@@ -1855,9 +1873,12 @@
         this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL),
         " 1");
       commands.push_back(std::move(runRule));
-#if !defined(CMAKE_BOOTSTRAP) && !defined(_WIN32)
-      addInstrumentationCommand(this->GetCMakeInstance()->GetInstrumentation(),
-                                commands);
+#ifndef CMAKE_BOOTSTRAP
+      // FIXME(#27079): This does not work for MSYS Makefiles.
+      if (this->GlobalGenerator->GetName() != "MSYS Makefiles") {
+        addInstrumentationCommand(
+          this->GetCMakeInstance()->GetInstrumentation(), commands);
+      }
 #endif
     }
     this->CreateCDCommand(commands, this->GetBinaryDirectory(),
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index 651b6d7..cc32fe2 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -14,6 +14,7 @@
 #include "cmDepends.h"
 #include "cmGeneratorOptions.h"
 #include "cmLocalCommonGenerator.h"
+#include "cmStateTypes.h"
 
 class cmCustomCommand;
 class cmCustomCommandGenerator;
@@ -43,6 +44,10 @@
    */
   void Generate() override;
 
+  std::string GetObjectOutputRoot(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const override;
+
   // this returns the relative path between the HomeOutputDirectory and this
   // local generators StartOutputDirectory
   std::string const& GetHomeRelativeOutputPath();
@@ -135,7 +140,8 @@
 
   /** Called from command-line hook to bring dependencies up to date
       for a target.  */
-  bool UpdateDependencies(std::string const& tgtInfo, bool verbose,
+  bool UpdateDependencies(std::string const& tgtInfo,
+                          std::string const& targetName, bool verbose,
                           bool color) override;
 
   /** Called from command-line hook to clear dependencies.  */
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 471681c..1d6d973 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -2231,7 +2231,12 @@
 std::string cmLocalVisualStudio7Generator::GetTargetDirectory(
   cmGeneratorTarget const* target) const
 {
-  std::string dir = cmStrCat(target->GetName(), ".dir");
+  std::string dir;
+  if (target->GetUseShortObjectNames()) {
+    dir = this->ComputeShortTargetDirectory(target);
+  } else {
+    dir = cmStrCat(target->GetName(), ".dir");
+  }
   return dir;
 }
 
diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx
index ae953d5..4ea3f1b 100644
--- a/Source/cmLocalVisualStudioGenerator.cxx
+++ b/Source/cmLocalVisualStudioGenerator.cxx
@@ -51,8 +51,14 @@
 
   for (auto const& si : mapping) {
     cmSourceFile const* sf = si.first;
-    std::string objectNameLower = cmSystemTools::LowerCase(
-      cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
+    std::string baseObjectName;
+    if (gt->GetUseShortObjectNames()) {
+      baseObjectName = this->GetShortObjectFileName(*sf);
+    } else {
+      baseObjectName =
+        cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+    }
+    std::string objectNameLower = cmSystemTools::LowerCase(baseObjectName);
     if (custom_ext) {
       objectNameLower += custom_ext;
     } else {
@@ -67,8 +73,13 @@
 
   for (auto& si : mapping) {
     cmSourceFile const* sf = si.first;
-    std::string objectName =
-      cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+    std::string objectName;
+    if (gt->GetUseShortObjectNames()) {
+      objectName = this->GetShortObjectFileName(*sf);
+    } else {
+      objectName =
+        cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+    }
     if (custom_ext) {
       objectName += custom_ext;
     } else {
@@ -84,8 +95,13 @@
   }
 }
 
-std::string cmLocalVisualStudioGenerator::GetObjectOutputRoot() const
+std::string cmLocalVisualStudioGenerator::GetObjectOutputRoot(
+  cmStateEnums::IntermediateDirKind kind) const
 {
+  if (this->UseShortObjectNames(kind)) {
+    return cmStrCat(this->GetCurrentBinaryDirectory(), '/',
+                    this->GetGlobalGenerator()->GetShortBinaryOutputDir());
+  }
   return this->GetCurrentBinaryDirectory();
 }
 
diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h
index eb0e4ad..fdc15be 100644
--- a/Source/cmLocalVisualStudioGenerator.h
+++ b/Source/cmLocalVisualStudioGenerator.h
@@ -10,6 +10,7 @@
 
 #include "cmGlobalVisualStudioGenerator.h"
 #include "cmLocalGenerator.h"
+#include "cmStateTypes.h"
 #include "cmVsProjectType.h"
 
 class cmCustomCommand;
@@ -51,7 +52,9 @@
     std::map<cmSourceFile const*, std::string>& mapping,
     cmGeneratorTarget const* = nullptr) override;
 
-  std::string GetObjectOutputRoot() const override;
+  std::string GetObjectOutputRoot(
+    cmStateEnums::IntermediateDirKind kind =
+      cmStateEnums::IntermediateDirKind::ObjectFiles) const override;
   bool AlwaysUsesCMFPaths() const override;
 
 protected:
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 786ef74..ec0fdb7 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -50,6 +50,7 @@
 #include "cmRange.h"
 #include "cmSourceFile.h"
 #include "cmSourceFileLocation.h"
+#include "cmStack.h"
 #include "cmState.h"
 #include "cmStateDirectory.h"
 #include "cmStateTypes.h"
@@ -1553,7 +1554,23 @@
   cmSystemTools::MakeDirectory(filesDir);
 
   assert(cmSystemTools::FileExists(currentStart, true));
-  this->AddDefinition(kCMAKE_PARENT_LIST_FILE, currentStart);
+
+  // In the top-most directory, cmake_minimum_required() may not have been
+  // called yet, so ApplyPolicyVersion() may not have handled the default
+  // policy value.  Check them here.
+  if (this->GetPolicyStatus(cmPolicies::CMP0198) == cmPolicies::WARN) {
+    if (cmValue defaultValue =
+          this->GetDefinition("CMAKE_POLICY_DEFAULT_CMP0198")) {
+      if (*defaultValue == "NEW") {
+        this->SetPolicy(cmPolicies::CMP0198, cmPolicies::NEW);
+      } else if (*defaultValue == "OLD") {
+        this->SetPolicy(cmPolicies::CMP0198, cmPolicies::OLD);
+      }
+    }
+  }
+
+  // Set CMAKE_PARENT_LIST_FILE for CMakeLists.txt based on CMP0198 policy
+  this->UpdateParentListFileVariable();
 
 #ifdef CMake_ENABLE_DEBUGGER
   if (this->GetCMakeInstance()->GetDebugAdapter()) {
@@ -4077,7 +4094,7 @@
   }
 
   // Deprecate old policies.
-  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0142 &&
+  if (status == cmPolicies::OLD && id <= cmPolicies::CMP0143 &&
       !(this->GetCMakeInstance()->GetIsInTryCompile() &&
         (
           // Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4092,6 +4109,12 @@
   }
 
   this->StateSnapshot.SetPolicy(id, status);
+
+  // Handle CMAKE_PARENT_LIST_FILE for CMP0198 policy changes
+  if (id == cmPolicies::CMP0198) {
+    this->UpdateParentListFileVariable();
+  }
+
   return true;
 }
 
@@ -4144,6 +4167,21 @@
                                         cmPolicies::WarnCompat::On);
 }
 
+void cmMakefile::UpdateParentListFileVariable()
+{
+  // CMP0198 determines CMAKE_PARENT_LIST_FILE behavior in CMakeLists.txt
+  if (this->GetPolicyStatus(cmPolicies::CMP0198) == cmPolicies::NEW) {
+    this->RemoveDefinition(kCMAKE_PARENT_LIST_FILE);
+  } else {
+    std::string currentSourceDir =
+      this->StateSnapshot.GetDirectory().GetCurrentSource();
+    std::string currentStart =
+      this->GetCMakeInstance()->GetCMakeListFile(currentSourceDir);
+
+    this->AddDefinition(kCMAKE_PARENT_LIST_FILE, currentStart);
+  }
+}
+
 cmMakefile::VariablePushPop::VariablePushPop(cmMakefile* m)
   : Makefile(m)
 {
@@ -4193,20 +4231,34 @@
   this->Makefile->PopMacroScope(this->ReportError);
 }
 
-cmMakefile::FindPackageStackRAII::FindPackageStackRAII(cmMakefile* mf,
-                                                       std::string const& name)
+cmFindPackageStackRAII::cmFindPackageStackRAII(cmMakefile* mf,
+                                               std::string const& name)
   : Makefile(mf)
 {
   this->Makefile->FindPackageStack =
     this->Makefile->FindPackageStack.Push(cmFindPackageCall{
       name,
+      cmPackageInformation(),
       this->Makefile->FindPackageStackNextIndex,
     });
   this->Makefile->FindPackageStackNextIndex++;
 }
 
-cmMakefile::FindPackageStackRAII::~FindPackageStackRAII()
+void cmFindPackageStackRAII::BindTop(cmPackageInformation*& value)
 {
+  if (this->Value) {
+    *this->Value = nullptr;
+  }
+  this->Value = &value;
+  value = &this->Makefile->FindPackageStack.cmStack::Top().PackageInfo;
+}
+
+cmFindPackageStackRAII::~cmFindPackageStackRAII()
+{
+  if (this->Value) {
+    *this->Value = nullptr;
+  }
+
   this->Makefile->FindPackageStackNextIndex =
     this->Makefile->FindPackageStack.Top().Index + 1;
   this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Pop();
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 89b3c2b..1790418 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -391,6 +391,9 @@
   void RecordPolicies(cmPolicies::PolicyMap& pm) const;
   //@}
 
+  /** Update CMAKE_PARENT_LIST_FILE based on CMP0198 policy status.  */
+  void UpdateParentListFileVariable();
+
   /** Helper class to push and pop policies automatically.  */
   class PolicyPushPop
   {
@@ -1031,17 +1034,7 @@
   // searches
   std::deque<std::vector<std::string>> FindPackageRootPathStack;
 
-  class FindPackageStackRAII
-  {
-    cmMakefile* Makefile;
-
-  public:
-    FindPackageStackRAII(cmMakefile* mf, std::string const& pkg);
-    ~FindPackageStackRAII();
-
-    FindPackageStackRAII(FindPackageStackRAII const&) = delete;
-    FindPackageStackRAII& operator=(FindPackageStackRAII const&) = delete;
-  };
+  friend class cmFindPackageStackRAII;
 
   class DebugFindPkgRAII
   {
diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx
index 613442d..30432cc 100644
--- a/Source/cmMakefileExecutableTargetGenerator.cxx
+++ b/Source/cmMakefileExecutableTargetGenerator.cxx
@@ -204,6 +204,12 @@
     objectDir = this->LocalGenerator->ConvertToOutputFormat(
       this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
       cmOutputConverter::SHELL);
+    std::string targetSupportDir =
+      this->GeneratorTarget->GetCMFSupportDirectory();
+
+    targetSupportDir = this->LocalGenerator->ConvertToOutputFormat(
+      this->LocalGenerator->MaybeRelativeToTopBinDir(targetSupportDir),
+      cmOutputConverter::SHELL);
 
     std::string target = this->LocalGenerator->ConvertToOutputFormat(
       this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput),
@@ -219,6 +225,7 @@
     vars.Objects = buildObjs.c_str();
     vars.ObjectDir = objectDir.c_str();
     vars.Target = target.c_str();
+    vars.TargetSupportDir = targetSupportDir.c_str();
     vars.LinkLibraries = linkLibs.c_str();
     vars.LanguageCompileFlags = langFlags.c_str();
     vars.LinkFlags = linkFlags.c_str();
@@ -550,6 +557,13 @@
       this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
       cmOutputConverter::SHELL);
     vars.ObjectDir = objectDir.c_str();
+    std::string targetSupportDir =
+      this->GeneratorTarget->GetCMFSupportDirectory();
+
+    targetSupportDir = this->LocalGenerator->ConvertToOutputFormat(
+      this->LocalGenerator->MaybeRelativeToTopBinDir(targetSupportDir),
+      cmOutputConverter::SHELL);
+    vars.TargetSupportDir = targetSupportDir.c_str();
     std::string target = this->LocalGenerator->ConvertToOutputFormat(
       this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
       cmOutputConverter::SHELL, useWatcomQuote);
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index de05d24..6feffbd 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -364,6 +364,12 @@
       this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
       cmOutputConverter::SHELL);
 
+    std::string targetSupportDir =
+      this->GeneratorTarget->GetCMFSupportDirectory();
+    targetSupportDir = this->LocalGenerator->ConvertToOutputFormat(
+      this->LocalGenerator->MaybeRelativeToTopBinDir(targetSupportDir),
+      cmOutputConverter::SHELL);
+
     std::string target = this->LocalGenerator->ConvertToOutputFormat(
       this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput),
       cmOutputConverter::SHELL);
@@ -376,6 +382,7 @@
 
     vars.Objects = buildObjs.c_str();
     vars.ObjectDir = objectDir.c_str();
+    vars.TargetSupportDir = targetSupportDir.c_str();
     vars.Target = target.c_str();
     vars.LinkLibraries = linkLibs.c_str();
     vars.ObjectsQuoted = buildObjs.c_str();
@@ -798,6 +805,14 @@
       cmOutputConverter::SHELL);
 
     vars.ObjectDir = objectDir.c_str();
+    std::string targetSupportDir =
+      this->GeneratorTarget->GetCMFSupportDirectory();
+
+    targetSupportDir = this->LocalGenerator->ConvertToOutputFormat(
+      this->LocalGenerator->MaybeRelativeToTopBinDir(targetSupportDir),
+      cmOutputConverter::SHELL);
+
+    vars.TargetSupportDir = targetSupportDir.c_str();
     std::string target = this->LocalGenerator->ConvertToOutputFormat(
       this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
       cmOutputConverter::SHELL, useWatcomQuote);
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 5187f5e..44de1fe 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -946,6 +946,12 @@
     this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
     cmOutputConverter::SHELL);
   vars.ObjectDir = objectDir.c_str();
+  std::string targetSupportDir =
+    this->GeneratorTarget->GetCMFSupportDirectory();
+  targetSupportDir = this->LocalGenerator->ConvertToOutputFormat(
+    this->LocalGenerator->MaybeRelativeToTopBinDir(targetSupportDir),
+    cmOutputConverter::SHELL);
+  vars.TargetSupportDir = targetSupportDir.c_str();
   std::string objectFileDir = cmSystemTools::GetFilenamePath(obj);
   objectFileDir = this->LocalGenerator->ConvertToOutputFormat(
     this->LocalGenerator->MaybeRelativeToCurBinDir(objectFileDir),
@@ -1542,6 +1548,7 @@
   //                          <home-src-dir> <start-src-dir>
   //                          <home-out-dir> <start-out-dir>
   //                          <dep-info> --color=$(COLOR)
+  //                          <target-name>
   //
   // This gives the dependency scanner enough information to recreate
   // the state of our local generator sufficiently for its needs.
@@ -1568,6 +1575,9 @@
   if (this->LocalGenerator->GetColorMakefile()) {
     depCmd << " \"--color=$(COLOR)\"";
   }
+  depCmd << ' '
+         << this->LocalGenerator->ConvertToOutputFormat(
+              this->GeneratorTarget->GetName(), cmOutputConverter::SHELL);
   commands.push_back(depCmd.str());
 
   // Make sure all custom command outputs in this target are built.
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 34092b3..e19f4ef 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -69,7 +69,7 @@
                        std::string const& message)
 {
   // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
-  static std::vector<unsigned long> const LogVersionsWithMessageV1{ 1 };
+  static std::vector<unsigned int> const LogVersionsWithMessageV1{ 1 };
 
   if (log.IsAnyLogVersionEnabled(LogVersionsWithMessageV1)) {
     log.BeginEvent("message-v1", mf);
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index e04f270..af18d21 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -332,6 +332,7 @@
     }
 
     vars.ObjectDir = "$OBJECT_DIR";
+    vars.TargetSupportDir = "$TARGET_SUPPORT_DIR";
 
     vars.Target = "$TARGET_FILE";
 
@@ -532,6 +533,7 @@
     }
 
     vars.ObjectDir = "$OBJECT_DIR";
+    vars.TargetSupportDir = "$TARGET_SUPPORT_DIR";
 
     vars.Target = "$TARGET_FILE";
 
@@ -1032,7 +1034,7 @@
                               vars["LINK_FLAGS"], frameworkPath, linkPath,
                               genTarget);
 
-  this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars);
+  this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, nullptr, vars);
 
   vars["MANIFESTS"] = this->GetManifests(config);
 
@@ -1075,6 +1077,14 @@
     this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
   this->EnsureDirectoryExists(objPath);
 
+  std::string const targetSupportPath =
+    this->GetGeneratorTarget()->GetCMFSupportDirectory();
+
+  vars["TARGET_SUPPORT_DIR"] =
+    this->GetLocalGenerator()->ConvertToOutputFormat(
+      this->ConvertToNinjaPath(targetSupportPath), cmOutputConverter::SHELL);
+  this->EnsureDirectoryExists(targetSupportPath);
+
   this->SetMsvcTargetPdbVariable(vars, config);
 
   std::string& linkLibraries = vars["LINK_LIBRARIES"];
@@ -1318,7 +1328,7 @@
                            this->TargetLinkLanguage(config), "CURRENT", false);
   }
 
-  this->addPoolNinjaVariable("JOB_POOL_LINK", gt, vars);
+  this->addPoolNinjaVariable("JOB_POOL_LINK", gt, nullptr, vars);
 
   this->UseLWYU = this->GetLocalGenerator()->AppendLWYUFlags(
     vars["LINK_FLAGS"], this->GetGeneratorTarget(),
@@ -1397,6 +1407,12 @@
     this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
   this->EnsureDirectoryExists(objPath);
 
+  std::string const targetSupportPath = gt->GetCMFSupportDirectory();
+  vars["TARGET_SUPPORT_DIR"] =
+    this->GetLocalGenerator()->ConvertToOutputFormat(
+      this->ConvertToNinjaPath(targetSupportPath), cmOutputConverter::SHELL);
+  this->EnsureDirectoryExists(targetSupportPath);
+
   std::string& linkLibraries = vars["LINK_LIBRARIES"];
   std::string& link_path = vars["LINK_PATH"];
   if (globalGen->IsGCCOnWindows()) {
@@ -1562,7 +1578,8 @@
   }
 
   // Add dependencies on swiftmodule files when using the swift linker
-  if (this->TargetLinkLanguage(config) == "Swift") {
+  if (!this->GetLocalGenerator()->IsSplitSwiftBuild() &&
+      this->TargetLinkLanguage(config) == "Swift") {
     if (cmComputeLinkInformation* cli =
           this->GeneratorTarget->GetLinkInformation(config)) {
       for (auto const& dependency : cli->GetItems()) {
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index b22ee1f..25f6d36 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -666,6 +666,7 @@
   vars.TargetPDB = "$TARGET_PDB";
   vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
   vars.ObjectDir = "$OBJECT_DIR";
+  vars.TargetSupportDir = "$TARGET_SUPPORT_DIR";
   vars.ObjectFileDir = "$OBJECT_FILE_DIR";
   vars.CudaCompileMode = "$CUDA_COMPILE_MODE";
   vars.ISPCHeader = "$ISPC_HEADER_FILE";
@@ -1377,6 +1378,8 @@
 {
   std::string const language = source->GetLanguage();
   std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(source);
+  std::string const targetSupportDir =
+    this->ConvertToNinjaPath(this->GeneratorTarget->GetCMFSupportDirectory());
   std::string const objectDir =
     this->ConvertToNinjaPath(this->GetObjectFileDir(config));
   std::string const objectFileName =
@@ -1411,6 +1414,12 @@
   vars["DEFINES"] = this->ComputeDefines(source, language, config);
   vars["INCLUDES"] = this->ComputeIncludes(source, language, config);
   vars["CONFIG"] = config;
+  if (this->GetGeneratorTarget()->GetUseShortObjectNames()) {
+    vars.emplace(
+      "description",
+      cmStrCat("Compiling object ", objectFileName, " from source ",
+               this->GetLocalGenerator()->GetRelativeSourceFileName(*source)));
+  }
 
   auto compilerLauncher = this->GetCompilerLauncher(language, config);
 
@@ -1460,8 +1469,8 @@
 
   if (firstForConfig) {
     this->ExportObjectCompileCommand(
-      language, sourceFilePath, objectDir, objectFileName, objectFileDir,
-      vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"],
+      language, sourceFilePath, objectDir, targetSupportDir, objectFileName,
+      objectFileDir, vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"],
       vars["TARGET_COMPILE_PDB"], vars["TARGET_PDB"], config, withScanning);
   }
 
@@ -1606,7 +1615,7 @@
     }
 
     this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
-                               ppBuild.Variables);
+                               source, ppBuild.Variables);
 
     this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
                                            ppBuild, commandLineLengthLimit);
@@ -1635,17 +1644,20 @@
 
   vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     objectDir, cmOutputConverter::SHELL);
+  vars["TARGET_SUPPORT_DIR"] =
+    this->GetLocalGenerator()->ConvertToOutputFormat(targetSupportDir,
+                                                     cmOutputConverter::SHELL);
   vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     objectFileDir, cmOutputConverter::SHELL);
 
   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
-                             vars);
+                             source, vars);
 
   if (!pchSources.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
     auto pchIt = pchSources.find(source->GetFullPath());
     if (pchIt != pchSources.end()) {
       this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER",
-                                 this->GetGeneratorTarget(), vars);
+                                 this->GetGeneratorTarget(), nullptr, vars);
     }
   }
 
@@ -1748,6 +1760,8 @@
   }
 
   std::string const sourceFilePath = this->GetCompiledSourceNinjaPath(source);
+  std::string const targetSupportDir =
+    this->ConvertToNinjaPath(this->GeneratorTarget->GetCMFSupportDirectory());
   std::string const bmiDir = this->ConvertToNinjaPath(
     cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
              this->GetGlobalGenerator()->ConfigDirectory(config)));
@@ -1799,9 +1813,10 @@
 
   if (firstForConfig) {
     this->ExportObjectCompileCommand(
-      language, sourceFilePath, bmiDir, bmiFileName, bmiFileDir, vars["FLAGS"],
-      vars["DEFINES"], vars["INCLUDES"], vars["TARGET_COMPILE_PDB"],
-      vars["TARGET_PDB"], config, WithScanning::Yes);
+      language, sourceFilePath, bmiDir, targetSupportDir, bmiFileName,
+      bmiFileDir, vars["FLAGS"], vars["DEFINES"], vars["INCLUDES"],
+      vars["TARGET_COMPILE_PDB"], vars["TARGET_PDB"], config,
+      WithScanning::Yes);
   }
 
   bmiBuild.Outputs.push_back(bmiFileName);
@@ -1836,7 +1851,7 @@
     }
 
     this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
-                               ppBuild.Variables);
+                               source, ppBuild.Variables);
 
     this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
                                            ppBuild, commandLineLengthLimit);
@@ -1860,11 +1875,14 @@
 
   vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     bmiDir, cmOutputConverter::SHELL);
+  vars["TARGET_SUPPORT_DIR"] =
+    this->GetLocalGenerator()->ConvertToOutputFormat(targetSupportDir,
+                                                     cmOutputConverter::SHELL);
   vars["OBJECT_FILE_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
     bmiFileDir, cmOutputConverter::SHELL);
 
   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
-                             vars);
+                             source, vars);
 
   bmiBuild.RspFile = cmStrCat(bmiFileName, ".rsp");
 
@@ -2203,11 +2221,12 @@
 
 void cmNinjaTargetGenerator::ExportObjectCompileCommand(
   std::string const& language, std::string const& sourceFileName,
-  std::string const& objectDir, std::string const& objectFileName,
-  std::string const& objectFileDir, std::string const& flags,
-  std::string const& defines, std::string const& includes,
-  std::string const& targetCompilePdb, std::string const& targetPdb,
-  std::string const& outputConfig, WithScanning withScanning)
+  std::string const& objectDir, std::string const& targetSupportDir,
+  std::string const& objectFileName, std::string const& objectFileDir,
+  std::string const& flags, std::string const& defines,
+  std::string const& includes, std::string const& targetCompilePdb,
+  std::string const& targetPdb, std::string const& outputConfig,
+  WithScanning withScanning)
 {
   if (!this->GeneratorTarget->GetPropertyAsBool("EXPORT_COMPILE_COMMANDS")) {
     return;
@@ -2254,6 +2273,7 @@
                                                 cmOutputConverter::SHELL);
   compileObjectVars.Object = escapedObjectFileName.c_str();
   compileObjectVars.ObjectDir = objectDir.c_str();
+  compileObjectVars.TargetSupportDir = targetSupportDir.c_str();
   compileObjectVars.ObjectFileDir = objectFileDir.c_str();
   compileObjectVars.Flags = fullFlags.c_str();
   compileObjectVars.Defines = defines.c_str();
@@ -2494,9 +2514,18 @@
 
 void cmNinjaTargetGenerator::addPoolNinjaVariable(
   std::string const& pool_property, cmGeneratorTarget* target,
-  cmNinjaVars& vars)
+  cmSourceFile const* source, cmNinjaVars& vars)
 {
-  cmValue pool = target->GetProperty(pool_property);
+  // First check the current source properties, then if not found, its target
+  // ones. Allows to override a target-wide compile pool with a source-specific
+  // one.
+  cmValue pool = {};
+  if (source) {
+    pool = source->GetProperty(pool_property);
+  }
+  if (!pool) {
+    pool = target->GetProperty(pool_property);
+  }
   if (pool) {
     vars["pool"] = *pool;
   }
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 7376a84..c4dc51f 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -193,11 +193,12 @@
 
   void ExportObjectCompileCommand(
     std::string const& language, std::string const& sourceFileName,
-    std::string const& objectDir, std::string const& objectFileName,
-    std::string const& objectFileDir, std::string const& flags,
-    std::string const& defines, std::string const& includes,
-    std::string const& targetCompilePdb, std::string const& targetPdb,
-    std::string const& outputConfig, WithScanning withScanning);
+    std::string const& objectDir, std::string const& targetSupportDir,
+    std::string const& objectFileName, std::string const& objectFileDir,
+    std::string const& flags, std::string const& defines,
+    std::string const& includes, std::string const& targetCompilePdb,
+    std::string const& targetPdb, std::string const& outputConfig,
+    WithScanning withScanning);
 
   void ExportSwiftObjectCompileCommand(
     std::vector<cmSourceFile const*> const& moduleSourceFiles,
@@ -236,8 +237,10 @@
   std::unique_ptr<cmOSXBundleGenerator> OSXBundleGenerator;
   std::set<std::string> MacContentFolders;
 
+  /// @param source may be nullptr.
   void addPoolNinjaVariable(std::string const& pool_property,
-                            cmGeneratorTarget* target, cmNinjaVars& vars);
+                            cmGeneratorTarget* target,
+                            cmSourceFile const* source, cmNinjaVars& vars);
 
   bool ForceResponseFile();
 
diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx
index e25da96..118b833 100644
--- a/Source/cmOSXBundleGenerator.cxx
+++ b/Source/cmOSXBundleGenerator.cxx
@@ -58,7 +58,7 @@
 
 void cmOSXBundleGenerator::CreateFramework(
   std::string const& targetName, std::string const& outpath,
-  std::string const& config, cmOSXBundleGenerator::SkipParts const& skipParts)
+  std::string const& config, cmOSXBundleGenerator::SkipParts skipParts)
 {
   if (this->MustSkip()) {
     return;
diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h
index bfd9aec..153cbcc 100644
--- a/Source/cmOSXBundleGenerator.h
+++ b/Source/cmOSXBundleGenerator.h
@@ -34,7 +34,7 @@
   // create a framework at a given root
   void CreateFramework(std::string const& targetName, std::string const& root,
                        std::string const& config,
-                       SkipParts const& skipParts = SkipParts{});
+                       SkipParts skipParts = SkipParts{});
 
   // create a cf bundle at a given root
   void CreateCFBundle(std::string const& targetName, std::string const& root,
diff --git a/Source/cmPackageInfoArguments.cxx b/Source/cmPackageInfoArguments.cxx
index 078f63d..d60e08c 100644
--- a/Source/cmPackageInfoArguments.cxx
+++ b/Source/cmPackageInfoArguments.cxx
@@ -60,6 +60,8 @@
     ENFORCE_REQUIRES("PACKAGE_INFO", this->LowerCase, "LOWER_CASE_FILE");
     ENFORCE_REQUIRES("PACKAGE_INFO", this->Appendix, "APPENDIX");
     ENFORCE_REQUIRES("PACKAGE_INFO", this->Version, "VERSION");
+    ENFORCE_REQUIRES("PACKAGE_INFO", this->License, "LICENSE");
+    ENFORCE_REQUIRES("PACKAGE_INFO", this->DefaultLicense, "DEFAULT_LICENSE");
     ENFORCE_REQUIRES("PACKAGE_INFO", this->Description, "DESCRIPTION");
     ENFORCE_REQUIRES("PACKAGE_INFO", this->Website, "HOMEPAGE_URL");
     ENFORCE_REQUIRES("PACKAGE_INFO", this->DefaultTargets, "DEFAULT_TARGETS");
@@ -73,6 +75,7 @@
   // Check for incompatible options.
   if (!this->Appendix.empty()) {
     ENFORCE_EXCLUSIVE("APPENDIX", this->Version, "VERSION");
+    ENFORCE_EXCLUSIVE("APPENDIX", this->License, "LICENSE");
     ENFORCE_EXCLUSIVE("APPENDIX", this->Description, "DESCRIPTION");
     ENFORCE_EXCLUSIVE("APPENDIX", this->Website, "HOMEPAGE_URL");
     ENFORCE_EXCLUSIVE("APPENDIX", this->DefaultTargets, "DEFAULT_TARGETS");
@@ -136,6 +139,10 @@
     }
   }
 
+  if (this->License.empty()) {
+    mapProjectValue(this->License, "SPDX_LICENSE"_s);
+  }
+
   if (this->Description.empty()) {
     mapProjectValue(this->Description, "DESCRIPTION"_s);
   }
diff --git a/Source/cmPackageInfoArguments.h b/Source/cmPackageInfoArguments.h
index a002197..9134bc1 100644
--- a/Source/cmPackageInfoArguments.h
+++ b/Source/cmPackageInfoArguments.h
@@ -56,6 +56,8 @@
   ArgumentParser::NonEmpty<std::string> Version;
   ArgumentParser::NonEmpty<std::string> VersionCompat;
   ArgumentParser::NonEmpty<std::string> VersionSchema;
+  ArgumentParser::NonEmpty<std::string> License;
+  ArgumentParser::NonEmpty<std::string> DefaultLicense;
   ArgumentParser::NonEmpty<std::string> Description;
   ArgumentParser::NonEmpty<std::string> Website;
   ArgumentParser::NonEmpty<std::vector<std::string>> DefaultTargets;
@@ -84,6 +86,9 @@
          &cmPackageInfoArguments::DefaultTargets);
     Bind(self, parser, "DEFAULT_CONFIGURATIONS"_s,
          &cmPackageInfoArguments::DefaultConfigs);
+    Bind(self, parser, "LICENSE"_s, &cmPackageInfoArguments::License);
+    Bind(self, parser, "DEFAULT_LICENSE"_s,
+         &cmPackageInfoArguments::DefaultLicense);
     Bind(self, parser, "DESCRIPTION"_s, &cmPackageInfoArguments::Description);
     Bind(self, parser, "HOMEPAGE_URL"_s, &cmPackageInfoArguments::Website);
 
diff --git a/Source/cmPackageInfoReader.cxx b/Source/cmPackageInfoReader.cxx
index dd6a13c..b684897 100644
--- a/Source/cmPackageInfoReader.cxx
+++ b/Source/cmPackageInfoReader.cxx
@@ -180,7 +180,7 @@
 }
 
 // Extract key name from value iterator as string_view.
-cm::string_view IterKey(Json::Value::const_iterator const& iter)
+cm::string_view IterKey(Json::Value::const_iterator iter)
 {
   char const* end;
   char const* const start = iter.memberName(&end);
@@ -479,6 +479,14 @@
     }
   }
 
+  // Check for a default license.
+  Json::Value const& defaultLicense = reader->Data["default_license"];
+  if (!defaultLicense.isNull()) {
+    reader->DefaultLicense = defaultLicense.asString();
+  } else if (parent) {
+    reader->DefaultLicense = parent->DefaultLicense;
+  }
+
   return reader;
 }
 
@@ -582,12 +590,14 @@
   }
 }
 
-void cmPackageInfoReader::SetMetaProperty(cmTarget* target,
-                                          cm::string_view property,
-                                          Json::Value const& value) const
+void cmPackageInfoReader::SetMetaProperty(
+  cmTarget* target, cm::string_view property, Json::Value const& value,
+  std::string const& defaultValue) const
 {
   if (!value.isNull()) {
     target->SetProperty(property.data(), value.asString());
+  } else if (!defaultValue.empty()) {
+    target->SetProperty(property.data(), defaultValue);
   }
 }
 
@@ -671,7 +681,8 @@
 
   // Add other information.
   if (configuration.empty()) {
-    this->SetMetaProperty(target, "SPDX_LICENSE"_s, data["license"]);
+    this->SetMetaProperty(target, "SPDX_LICENSE"_s, data["license"],
+                          this->DefaultLicense);
   }
 }
 
@@ -681,6 +692,7 @@
 {
   // Create the imported target.
   cmTarget* const target = makefile->AddImportedTarget(name, type, false);
+  target->SetOrigin(cmTarget::Origin::Cps);
 
   // Set default configurations.
   if (!this->DefaultConfigurations.empty()) {
@@ -707,7 +719,7 @@
   Json::Value const& components = this->Data["components"];
 
   for (auto ci = components.begin(), ce = components.end(); ci != ce; ++ci) {
-    cm::string_view const& name = IterKey(ci);
+    cm::string_view const name = IterKey(ci);
     std::string const& type =
       cmSystemTools::LowerCase((*ci)["type"].asString());
 
@@ -786,7 +798,7 @@
 
   for (auto ci = components.begin(), ce = components.end(); ci != ce; ++ci) {
     // Get component name and look up target.
-    cm::string_view const& name = IterKey(ci);
+    cm::string_view const name = IterKey(ci);
     auto const& ti = this->ComponentTargets.find(std::string{ name });
     if (ti == this->ComponentTargets.end()) {
       status.SetError(cmStrCat("component "_s, name, " was not found"_s));
diff --git a/Source/cmPackageInfoReader.h b/Source/cmPackageInfoReader.h
index 3173f66..4597e83 100644
--- a/Source/cmPackageInfoReader.h
+++ b/Source/cmPackageInfoReader.h
@@ -98,7 +98,8 @@
                          cm::string_view configuration,
                          Json::Value const& value) const;
   void SetMetaProperty(cmTarget* target, cm::string_view property,
-                       Json::Value const& value) const;
+                       Json::Value const& value,
+                       std::string const& defaultValue = {}) const;
 
   std::string ResolvePath(std::string path) const;
 
@@ -108,4 +109,5 @@
 
   std::map<std::string, cmTarget*> ComponentTargets;
   std::vector<std::string> DefaultConfigurations;
+  std::string DefaultLicense;
 };
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index b6ef05e..f9b28cf 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -589,7 +589,14 @@
          "The CMakeDetermineVSServicePack module is removed.", 4, 1, 0, WARN) \
   SELECT(POLICY, CMP0197,                                                     \
          "MSVC link -machine: flag is not in CMAKE_*_LINKER_FLAGS.", 4, 1, 0, \
-         WARN)
+         WARN)                                                                \
+  SELECT(POLICY, CMP0198,                                                     \
+         "CMAKE_PARENT_LIST_FILE is not defined in CMakeLists.txt.", 4, 2, 0, \
+         WARN)                                                                \
+  SELECT(                                                                     \
+    POLICY, CMP0199,                                                          \
+    "$<CONFIG:cfgs> only matches the configuration of the consumed target.",  \
+    4, 2, 0, WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
@@ -637,7 +644,8 @@
   F(CMP0179)                                                                  \
   F(CMP0181)                                                                  \
   F(CMP0182)                                                                  \
-  F(CMP0195)
+  F(CMP0195)                                                                  \
+  F(CMP0199)
 
 #define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F)                                  \
   F(CMP0116)                                                                  \
diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx
index 1a94eb9..3decfff 100644
--- a/Source/cmProjectCommand.cxx
+++ b/Source/cmProjectCommand.cxx
@@ -38,6 +38,7 @@
 {
   cm::optional<std::string> Version;
   cm::optional<std::string> CompatVersion;
+  cm::optional<std::string> License;
   cm::optional<std::string> Description;
   cm::optional<std::string> HomepageURL;
   cm::optional<ArgumentParser::MaybeEmpty<std::vector<std::string>>> Languages;
@@ -72,11 +73,12 @@
     .Bind("LANGUAGES"_s, prArgs.Languages);
 
   cmMakefile& mf = status.GetMakefile();
-  bool enableCompatVersion = cmExperimental::HasSupportEnabled(
+  bool enablePackageInfo = cmExperimental::HasSupportEnabled(
     mf, cmExperimental::Feature::ExportPackageInfo);
 
-  if (enableCompatVersion) {
+  if (enablePackageInfo) {
     parser.Bind("COMPAT_VERSION"_s, prArgs.CompatVersion);
+    parser.Bind("SPDX_LICENSE"_s, prArgs.License);
   }
 
   if (args.empty()) {
@@ -273,6 +275,7 @@
   createVariables("VERSION_PATCH"_s, version_components[2]);
   createVariables("VERSION_TWEAK"_s, version_components[3]);
   createVariables("COMPAT_VERSION"_s, prArgs.CompatVersion.value_or(""));
+  createVariables("SPDX_LICENSE"_s, prArgs.License.value_or(""));
   createVariables("DESCRIPTION"_s, prArgs.Description.value_or(""));
   createVariables("HOMEPAGE_URL"_s, prArgs.HomepageURL.value_or(""));
 
diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx
index 36d75af..0de417d 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -325,8 +325,8 @@
 
 cmQtAutoGenInitializer::cmQtAutoGenInitializer(
   cmQtAutoGenGlobalInitializer* globalInitializer,
-  cmGeneratorTarget* genTarget, IntegerVersion const& qtVersion,
-  bool mocEnabled, bool uicEnabled, bool rccEnabled, bool globalAutogenTarget,
+  cmGeneratorTarget* genTarget, IntegerVersion qtVersion, bool mocEnabled,
+  bool uicEnabled, bool rccEnabled, bool globalAutogenTarget,
   bool globalAutoRccTarget)
   : GlobalInitializer(globalInitializer)
   , GenTarget(genTarget)
@@ -460,20 +460,31 @@
     // Collapsed current binary directory
     std::string const cbd = cmSystemTools::CollapseFullPath(
       std::string(), this->Makefile->GetCurrentBinaryDirectory());
+    std::string infoDir;
+    std::string buildDir;
+    auto idirkind = cmStateEnums::IntermediateDirKind::QtAutogenMetadata;
+    if (this->GenTarget->GetUseShortObjectNames(idirkind)) {
+      infoDir = cmSystemTools::CollapseFullPath(
+        std::string(),
+        cmStrCat(this->GenTarget->GetSupportDirectory(idirkind),
+                 "/autogen_info"));
+      buildDir = cmSystemTools::CollapseFullPath(
+        std::string(),
+        cmStrCat(this->GenTarget->GetSupportDirectory(idirkind), "/autogen"));
+    } else {
+      infoDir = cmStrCat(cbd, "/CMakeFiles/", this->GenTarget->GetName(),
+                         "_autogen.dir");
+      buildDir = cmStrCat(cbd, '/', this->GenTarget->GetName(), "_autogen");
+    }
 
     // Info directory
-    // TODO: Split this? `AutogenInfo.json` is expected to always be under the
-    // `CMakeFiles` directory, but not all generators places its `<tgt>.dir`
-    // directories there.
-    this->Dir.Info = cmStrCat(cbd, "/CMakeFiles/", this->GenTarget->GetName(),
-                              "_autogen.dir");
+    this->Dir.Info = infoDir;
     cmSystemTools::ConvertToUnixSlashes(this->Dir.Info);
 
     // Build directory
     this->Dir.Build = this->GenTarget->GetSafeProperty("AUTOGEN_BUILD_DIR");
     if (this->Dir.Build.empty()) {
-      this->Dir.Build =
-        cmStrCat(cbd, '/', this->GenTarget->GetName(), "_autogen");
+      this->Dir.Build = buildDir;
     }
     cmSystemTools::ConvertToUnixSlashes(this->Dir.Build);
     this->Dir.RelativeBuild =
diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h
index 09015fe..afb3bfa 100644
--- a/Source/cmQtAutoGenInitializer.h
+++ b/Source/cmQtAutoGenInitializer.h
@@ -93,7 +93,7 @@
 
   cmQtAutoGenInitializer(cmQtAutoGenGlobalInitializer* globalInitializer,
                          cmGeneratorTarget* genTarget,
-                         IntegerVersion const& qtVersion, bool mocEnabled,
+                         IntegerVersion qtVersion, bool mocEnabled,
                          bool uicEnabled, bool rccEnabled,
                          bool globalAutogenTarget, bool globalAutoRccTarget);
 
diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h
index f8ea90d..486d1c9 100644
--- a/Source/cmQtAutoGenerator.h
+++ b/Source/cmQtAutoGenerator.h
@@ -88,7 +88,7 @@
   // -- Info options
   std::string const& InfoFile() const { return this->InfoFile_; }
   std::string const& InfoDir() const { return this->InfoDir_; }
-  cmFileTime const& InfoFileTime() const { return this->InfoFileTime_; }
+  cmFileTime InfoFileTime() const { return this->InfoFileTime_; }
   std::string const& InfoConfig() const { return this->InfoConfig_; }
   std::string const& ExecutableConfig() const
   {
diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx
index 01b6a66..4892b7c 100644
--- a/Source/cmRulePlaceholderExpander.cxx
+++ b/Source/cmRulePlaceholderExpander.cxx
@@ -77,6 +77,11 @@
       return this->ReplaceValues->Object;
     }
   }
+  if (this->ReplaceValues->TargetSupportDir) {
+    if (variable == "TARGET_SUPPORT_DIR") {
+      return this->ReplaceValues->TargetSupportDir;
+    }
+  }
   if (this->ReplaceValues->ObjectDir) {
     if (variable == "OBJECT_DIR") {
       return this->ReplaceValues->ObjectDir;
diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h
index 598a8ed..d0c3687 100644
--- a/Source/cmRulePlaceholderExpander.h
+++ b/Source/cmRulePlaceholderExpander.h
@@ -48,6 +48,7 @@
     char const* DynDepFile = nullptr;
     char const* Output = nullptr;
     char const* Object = nullptr;
+    char const* TargetSupportDir = nullptr;
     char const* ObjectDir = nullptr;
     char const* ObjectFileDir = nullptr;
     char const* Flags = nullptr;
diff --git a/Source/cmSPDXSerializer.cxx b/Source/cmSPDXSerializer.cxx
new file mode 100644
index 0000000..7d22103
--- /dev/null
+++ b/Source/cmSPDXSerializer.cxx
@@ -0,0 +1,1375 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include "cmSPDXSerializer.h"
+
+#include <new>
+#include <string>
+
+#include <cm/optional>
+
+#include <cm3p/json/value.h>
+
+// Serialization Utilities
+
+template <typename T>
+void addVectorSPDXValue(Json::Value& obj, std::string const& key,
+                        std::vector<T> const& vec)
+{
+  auto& list = obj[key];
+  list = Json::Value(Json::arrayValue);
+  for (auto const& val : vec) {
+    list.append(val.toJsonLD());
+  }
+}
+
+template <>
+void addVectorSPDXValue(Json::Value& obj, std::string const& key,
+                        std::vector<std::string> const& vec)
+{
+  auto& list = obj[key];
+  list = Json::Value(Json::arrayValue);
+  for (auto const& val : vec) {
+    list.append(val);
+  }
+}
+
+template <typename T>
+void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
+                          cm::optional<std::vector<T>> const& opt)
+{
+  if (opt) {
+    addVectorSPDXValue(obj, key, *opt);
+  }
+}
+
+template <typename T>
+void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
+                          cm::optional<T> const& opt)
+{
+  if (opt) {
+    obj[key] = opt->toJsonLD();
+  }
+}
+
+template <>
+void addOptionalSPDXValue(Json::Value& obj, std::string const& key,
+                          cm::optional<std::string> const& opt)
+{
+  if (opt) {
+    obj[key] = *opt;
+  }
+}
+
+// Base Class
+
+cmSPDXSerializationBase::SPDXTypeId cmSPDXSerializationBase::getTypeId() const
+{
+  return TypeId;
+}
+
+cmSPDXSerializationBase::cmSPDXSerializationBase(SPDXTypeId id)
+  : TypeId(id)
+{
+}
+
+cmSPDXSerializationBase::cmSPDXSerializationBase(SPDXTypeId id,
+                                                 std::string nodeId)
+  : NodeId(std::move(nodeId))
+  , TypeId(id)
+{
+}
+
+// Convenience Classes
+
+cmSPDXIdentifierReference::cmSPDXIdentifierReference()
+  : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE)
+{
+}
+cmSPDXIdentifierReference::cmSPDXIdentifierReference(
+  cmSPDXSerializationBase const& ref)
+  : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE, ref.NodeId)
+{
+}
+cmSPDXIdentifierReference::cmSPDXIdentifierReference(std::string const& ref)
+  : cmSPDXSerializationBase(CM_IDENTIFIER_REFERENCE, ref)
+{
+}
+
+Json::Value cmSPDXIdentifierReference::toJsonLD() const
+{
+  return NodeId;
+}
+
+cmSPDXNonElementBase::cmSPDXNonElementBase(SPDXTypeId id)
+  : cmSPDXSerializationBase(id)
+{
+}
+
+Json::Value cmSPDXNonElementBase::toJsonLD() const
+{
+  Json::Value obj(Json::objectValue);
+  obj["@id"] = NodeId;
+  return obj;
+}
+
+// SPDX Core Enums
+
+cmSPDXAnnotationType::cmSPDXAnnotationType(cmSPDXAnnotationTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXAnnotationType::toJsonLD() const
+{
+  switch (TypeId) {
+    case OTHER:
+      return "other";
+    case REVIEW:
+      return "review";
+    default:
+      return "INVALID_ANNOTATION_TYPE_ID";
+  }
+}
+
+cmSPDXExternalIdentifierType::cmSPDXExternalIdentifierType(
+  cmSPDXExternalIdentifierTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXExternalIdentifierType::toJsonLD() const
+{
+  switch (TypeId) {
+    case CPE22:
+      return "cpe22";
+    case CPE23:
+      return "cpe23";
+    case CVE:
+      return "cve";
+    case EMAIL:
+      return "email";
+    case GITOID:
+      return "gitoid";
+    case OTHER:
+      return "other";
+    case PACKAGE_URL:
+      return "packageUrl";
+    case SECURITY_OTHER:
+      return "securityOther";
+    case SWHID:
+      return "swhid";
+    case SWID:
+      return "swid";
+    case URL_SCHEME:
+      return "urlScheme";
+    default:
+      return "INVALID_EXTERNAL_IDENTIFIER_TYPE_ID";
+  }
+}
+
+cmSPDXExternalRefType::cmSPDXExternalRefType(cmSPDXExternalRefTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXExternalRefType::toJsonLD() const
+{
+  switch (TypeId) {
+    case ALT_DOWNLOAD_LOCATION:
+      return "altDownloadLocation:";
+    case ALT_WEB_PAGE:
+      return "altWebPage";
+    case BINARY_ARTIFACT:
+      return "binaryArtifact";
+    case BOWER:
+      return "bower";
+    case BUILD_META:
+      return "buildMeta";
+    case BUILD_SYSTEM:
+      return "buildSystem";
+    case CERTIFICATION_REPORT:
+      return "certificationReport";
+    case CHAT:
+      return "chat";
+    case COMPONENT_ANALYSIS_REPORT:
+      return "componentAnalysisReport";
+    case CWE:
+      return "cwe";
+    case DOCUMENTATION:
+      return "documentation";
+    case DYNAMIC_ANALYSIS_REPORT:
+      return "dynamicAnalysisReport";
+    case EOL_NOTICE:
+      return "eolNotice";
+    case EXPORT_CONTROL_ASSESSMENT:
+      return "exportControlAssessment";
+    case FUNDING:
+      return "funding";
+    case ISSUE_TRACKER:
+      return "issueTracker";
+    case LICENSE:
+      return "license";
+    case MAILING_LIST:
+      return "mailingList";
+    case MAVEN_CENTRAL:
+      return "mavenCentral";
+    case METRICS:
+      return "metrics";
+    case NPM:
+      return "npm";
+    case NUGET:
+      return "nuget";
+    case OTHER:
+      return "other";
+    case PRIVACY_ASSESSMENT:
+      return "privacyAssessment";
+    case PRODUCT_METADATA:
+      return "productMetadata";
+    case PURCHASE_ORDER:
+      return "purchaseOrder";
+    case QUALITY_ASSESSMENT_REPORT:
+      return "qualityAssessmentReport";
+    case RELEASE_HISTORY:
+      return "releaseHistory";
+    case RELEASE_NOTES:
+      return "releaseNotes";
+    case RISK_ASSESSMENT:
+      return "riskAssessment";
+    case RUNTIME_ANALYSIS_REPORT:
+      return "runtimeAnalysisReport";
+    case SECURE_SOFTWARE_ATTESTATION:
+      return "secureSoftwareAttestation";
+    case SECURITY_ADVERSARY_MODEL:
+      return "securityAdversaryModel";
+    case SECURITY_ADVISORY:
+      return "securityAdvisory";
+    case SECURITY_FIX:
+      return "securityFix";
+    case SECURITY_OTHER:
+      return "securityOther";
+    case SECURITY_PEN_TEST_REPORT:
+      return "securityPenTestReport";
+    case SECURITY_POLICY:
+      return "securityPolicy";
+    case SECURITY_THREAT_MODEL:
+      return "securityThreatModel";
+    case SOCIAL_MEDIA:
+      return "socialMedia";
+    case SOURCE_ARTIFACT:
+      return "sourceArtifact";
+    case STATIC_ANALYSIS_REPORT:
+      return "staticAnalysisReport";
+    case SUPPORT:
+      return "support";
+    case VCS:
+      return "vcs";
+    case VULNERABILITY_DISCLOSURE_REPORT:
+      return "vulnerabilityDisclosureReport";
+    case VULNERABILITY_EXPLOITABILITY_ASSESSMENT:
+      return "vulnerabilityExploitabilityAssessment";
+    default:
+      return "INVALID_EXTERNAL_REF_TYPE_ID";
+  }
+}
+
+cmSPDXHashAlgorithm::cmSPDXHashAlgorithm(cmSPDXHashAlgorithmId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXHashAlgorithm::toJsonLD() const
+{
+  switch (TypeId) {
+    case ADLER32:
+      return "adler32";
+    case BLAKE2B256:
+      return "blake2b256";
+    case BLAKE2B384:
+      return "blake2b384";
+    case BLAKE2B512:
+      return "blake2b512";
+    case BLAKE3:
+      return "blake3";
+    case CRYSTALS_DILITHIUM:
+      return "crystalsDilithium";
+    case CRYSTALS_KYBER:
+      return "crystalsLyber";
+    case FALCON:
+      return "falcon";
+    case MD2:
+      return "md2";
+    case MD4:
+      return "md4";
+    case MD5:
+      return "md5";
+    case MD6:
+      return "md6";
+    case OTHER:
+      return "other";
+    case SHA1:
+      return "sha1";
+    case SHA224:
+      return "sha224";
+    case SHA256:
+      return "sha256";
+    case SHA384:
+      return "sha384";
+    case SHA3_224:
+      return "sha3_224";
+    case SHA3_256:
+      return "sha3_256";
+    case SHA3_384:
+      return "sha3_384";
+    case SHA3_512:
+      return "sha3_512";
+    case SHA512:
+      return "sha512";
+    default:
+      return "INVALID_HASH_TYPE_ID";
+  }
+}
+
+cmSPDXLifecycleScopeType::cmSPDXLifecycleScopeType(
+  cmSPDXLifecycleScopeTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXLifecycleScopeType::toJsonLD() const
+{
+  switch (TypeId) {
+    case BUILD:
+      return "build";
+    case DESIGN:
+      return "design";
+    case DEVELOPMENT:
+      return "development";
+    case OTHER:
+      return "other";
+    case RUNTIME:
+      return "runtime";
+    case TEST:
+      return "test";
+    default:
+      return "INVALID_LIFECYCLE_SCOPE_TYPE_ID";
+  }
+}
+
+cmSPDXProfileIdentifierType::cmSPDXProfileIdentifierType(
+  cmSPDXProfileIdentifierTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXProfileIdentifierType::toJsonLD() const
+{
+  switch (TypeId) {
+    case AI:
+      return "ai";
+    case BUILD:
+      return "build";
+    case CORE:
+      return "code";
+    case DATASET:
+      return "dataset";
+    case EXPANDED_LICENSING:
+      return "expandedLicensing";
+    case EXTENSION:
+      return "extension";
+    case LITE:
+      return "lite";
+    case SECURITY:
+      return "security";
+    case SIMPLE_LICENSING:
+      return "simpleLicensing";
+    case SOFTWARE:
+      return "software";
+    default:
+      return "INVALID_PROFILE_IDENTIFIER_TYPE_ID";
+  }
+}
+
+cmSPDXRelationshipCompletenessType::cmSPDXRelationshipCompletenessType(
+  cmSPDXRelationshipCompletenessTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXRelationshipCompletenessType::toJsonLD() const
+{
+  switch (TypeId) {
+    case COMPLETE:
+      return "complete";
+    case INCOMPLETE:
+      return "incomplete";
+    case NO_ASSERTION:
+      return "noAssertion";
+    default:
+      return "INVALID_RELATIONSHIP_COMPLETENESS_TYPE_ID";
+  }
+}
+
+cmSPDXRelationshipType::cmSPDXRelationshipType(cmSPDXRelationshipTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXRelationshipType::toJsonLD() const
+{
+  switch (TypeId) {
+    case AFFECTS:
+      return "affects";
+    case AMENDED_BY:
+      return "amendedBy";
+    case ANCESTOR_OF:
+      return "ancestorOf";
+    case AVAILABLE_FROM:
+      return "availableFrom";
+    case CONFIGURES:
+      return "configures";
+    case CONTAINS:
+      return "contains";
+    case COORDINATED_BY:
+      return "coordinatedBy";
+    case COPIED_TO:
+      return "copiedTo";
+    case DELEGATED_TO:
+      return "delegatedTo";
+    case DEPENDS_ON:
+      return "dependsOn";
+    case DESCENDANT_OF:
+      return "descendantOf";
+    case DESCRIBES:
+      return "describes";
+    case DOES_NOT_AFFECT:
+      return "doesNotAffect";
+    case EXPANDS_TO:
+      return "expandsTo";
+    case EXPLOIT_CREATED_BY:
+      return "exploitCreatedBy";
+    case FIXED_BY:
+      return "fixedBy";
+    case FIXED_IN:
+      return "fixedIn";
+    case FOUND_BY:
+      return "foundBy";
+    case GENERATES:
+      return "generates";
+    case HAS_ADDED_FILE:
+      return "hasAddedFile";
+    case HAS_ASSESSMENT_FOR:
+      return "hasAssessmentFor";
+    case HAS_ASSOCIATED_VULNERABILITY:
+      return "hasAssociatedVulnerability";
+    case HAS_CONCLUDED_LICENSE:
+      return "hasConcludedLicense";
+    case HAS_DATA_FILE:
+      return "hasDataFile";
+    case HAS_DECLARED_LICENSE:
+      return "hasDeclaredLicense";
+    case HAS_DELETED_FILE:
+      return "hasDeletedFile";
+    case HAS_DEPENDENCY_MANIFEST:
+      return "hasDependencyManifest";
+    case HAS_DISTRIBUTION_ARTIFACT:
+      return "hasDistributionArtifact";
+    case HAS_DOCUMENTATION:
+      return "hasDocumentation";
+    case HAS_DYNAMIC_LINK:
+      return "hasDynamicLink";
+    case HAS_EVIDENCE:
+      return "hasEvidence";
+    case HAS_EXAMPLE:
+      return "hasExample";
+    case HAS_HOST:
+      return "hasHost";
+    case HAS_INPUT:
+      return "hasInput";
+    case HAS_METADATA:
+      return "hasMetadata";
+    case HAS_OPTIONAL_COMPONENT:
+      return "hasOptionalComponent";
+    case HAS_OPTIONAL_DEPENDENCY:
+      return "hasOptionalDependency";
+    case HAS_OUTPUT:
+      return "hasOutput";
+    case HAS_PREREQUISITE:
+      return "hasPrerequisite";
+    case HAS_PROVIDED_DEPENDENCY:
+      return "hasProvidedDependency";
+    case HAS_REQUIREMENT:
+      return "hasRequirement";
+    case HAS_SPECIFICATION:
+      return "hasSpecification";
+    case HAS_STATIC_LINK:
+      return "hasStaticLink";
+    case HAS_TEST:
+      return "hasTest";
+    case HAS_TEST_CASE:
+      return "hasTestCase";
+    case HAS_VARIANT:
+      return "hasVariant";
+    case INVOKED_BY:
+      return "invokedBy";
+    case MODIFIED_BY:
+      return "modifiedBy";
+    case OTHER:
+      return "other";
+    case PACKAGED_BY:
+      return "packagedBy";
+    case PATCHED_BY:
+      return "patchedBy";
+    case PUBLISHED_BY:
+      return "publishedBy";
+    case REPORTED_BY:
+      return "reportedBy";
+    case REPUBLISHED_BY:
+      return "republishedBy";
+    case SERIALIZED_IN_ARTIFACT:
+      return "serializedInArtifact";
+    case TESTED_ON:
+      return "testedOn";
+    case TRAINED_ON:
+      return "trainedOn";
+    case UNDER_INVESTIGATION_FOR:
+      return "underInvestigationFor";
+    case USES_TOOL:
+      return "usesTool";
+    default:
+      return "INVALID_RELATIONSHIP_TYPE_ID";
+  }
+}
+
+cmSPDXSupportType::cmSPDXSupportType(cmSPDXSupportTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXSupportType::toJsonLD() const
+{
+  switch (TypeId) {
+    case DEPLOYED:
+      return "deployed";
+    case DEVELOPMENT:
+      return "development";
+    case END_OF_SUPPORT:
+      return "endOfSupport";
+    case LIMITED_SUPPORT:
+      return "limitedSupport";
+    case NO_ASSERTION:
+      return "noAssertion";
+    case NO_SUPPORT:
+      return "noSupport";
+    case SUPPORT:
+      return "support";
+    default:
+      return "INVALID_SUPPORT_TYPE_ID";
+  }
+}
+
+// SPDX Core NonElement Classes, Abstract
+
+cmSPDXIntegrityMethod::cmSPDXIntegrityMethod(SPDXTypeId id)
+  : cmSPDXNonElementBase(id)
+{
+}
+
+Json::Value cmSPDXIntegrityMethod::toJsonLD() const
+{
+  auto obj = cmSPDXNonElementBase::toJsonLD();
+  addOptionalSPDXValue(obj, "comment", Comment);
+  return obj;
+}
+
+// SPDX Core NonElement Classes, Concrete
+
+cmSPDXCreationInfo::cmSPDXCreationInfo()
+  : cmSPDXNonElementBase(CORE_CREATION_INFO)
+{
+}
+
+Json::Value cmSPDXCreationInfo::toJsonLD() const
+{
+  auto obj = cmSPDXNonElementBase::toJsonLD();
+  obj["type"] = "CreationInfo";
+  addOptionalSPDXValue(obj, "Comment", Comment);
+  obj["created"] = Created;
+  addVectorSPDXValue(obj, "createdBy", CreatedBy);
+  addOptionalSPDXValue(obj, "createdUsing", CreatedUsing);
+  return obj;
+}
+
+cmSPDXDictionaryEntry::cmSPDXDictionaryEntry()
+  : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
+{
+}
+cmSPDXDictionaryEntry::cmSPDXDictionaryEntry(std::string key)
+  : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
+  , Key(std::move(key))
+{
+}
+cmSPDXDictionaryEntry::cmSPDXDictionaryEntry(std::string key, std::string val)
+  : cmSPDXNonElementBase(CORE_DICTIONARY_ENTRY)
+  , Key(std::move(key))
+  , Value(std::move(val))
+{
+}
+
+Json::Value cmSPDXDictionaryEntry::toJsonLD() const
+{
+  auto obj = cmSPDXNonElementBase::toJsonLD();
+  obj["type"] = "DictionaryEntry";
+  obj["key"] = Key;
+  addOptionalSPDXValue(obj, "value", Value);
+  return obj;
+}
+
+cmSPDXExternalIdentifier::cmSPDXExternalIdentifier()
+  : cmSPDXNonElementBase(CORE_EXTERNAL_IDENTIFIER)
+{
+}
+
+Json::Value cmSPDXExternalIdentifier::toJsonLD() const
+{
+  auto obj = cmSPDXNonElementBase::toJsonLD();
+  obj["type"] = "ExternalIdentifier";
+  addOptionalSPDXValue(obj, "comment", Comment);
+  obj["externalIdentifierType"] = ExternalIdentifierType.toJsonLD();
+  obj["identifier"] = Identifier;
+  addOptionalSPDXValue(obj, "identifierLocator", IdentifierLocator);
+  addOptionalSPDXValue(obj, "issuingAuthority", IssuingAuthority);
+  return obj;
+}
+
+cmSPDXExternalMap::cmSPDXExternalMap()
+  : cmSPDXNonElementBase(CORE_EXTERNAL_MAP)
+{
+}
+
+Json::Value cmSPDXExternalMap::toJsonLD() const
+{
+  auto obj = cmSPDXNonElementBase::toJsonLD();
+  obj["type"] = "ExternalMap";
+  addOptionalSPDXValue(obj, "definingArtifact", DefiningArtifact);
+  obj["externalSpdxId"] = ExternalSpdxId;
+  addOptionalSPDXValue(obj, "locationHint", LocationHint);
+  addOptionalSPDXValue(obj, "integrityMethod", IntegrityMethod);
+  return obj;
+}
+
+cmSPDXExternalRef::cmSPDXExternalRef()
+  : cmSPDXNonElementBase(CORE_EXTERNAL_REF)
+{
+}
+
+Json::Value cmSPDXExternalRef::toJsonLD() const
+{
+  auto obj = cmSPDXNonElementBase::toJsonLD();
+  obj["type"] = "ExternalRef";
+  addOptionalSPDXValue(obj, "comment", Comment);
+  addOptionalSPDXValue(obj, "contentType", ContentType);
+  addOptionalSPDXValue(obj, "externalRefType", ExternalRefType);
+  addOptionalSPDXValue(obj, "locator", Locator);
+  return obj;
+}
+
+cmSPDXHash::cmSPDXHash()
+  : cmSPDXIntegrityMethod(CORE_HASH)
+{
+}
+
+Json::Value cmSPDXHash::toJsonLD() const
+{
+  auto obj = cmSPDXIntegrityMethod::toJsonLD();
+  obj["type"] = "Hash";
+  obj["algorithm"] = Algorithm.toJsonLD();
+  obj["hashValue"] = HashValue;
+  return obj;
+}
+
+cmSPDXNamespaceMap::cmSPDXNamespaceMap()
+  : cmSPDXNonElementBase(CORE_NAMESPACE_MAP)
+{
+}
+
+Json::Value cmSPDXNamespaceMap::toJsonLD() const
+{
+  auto obj = cmSPDXNonElementBase::toJsonLD();
+  obj["type"] = "NamespaceMap";
+  obj["namespace"] = Namespace;
+  obj["prefix"] = Namespace;
+  return obj;
+}
+
+cmSPDXPackageVerificationCode::cmSPDXPackageVerificationCode()
+  : cmSPDXIntegrityMethod(CORE_PACKAGE_VERIFICATION_CODE)
+{
+}
+
+Json::Value cmSPDXPackageVerificationCode::toJsonLD() const
+{
+  auto obj = cmSPDXIntegrityMethod::toJsonLD();
+  obj["type"] = "PackageVerificationCode";
+  obj["algorithm"] = Algorithm.toJsonLD();
+  obj["hashValue"] = HashValue;
+  return obj;
+}
+
+cmSPDXPositiveIntegerRange::cmSPDXPositiveIntegerRange(
+  unsigned int beingIntegerRange, unsigned int endIntegerRange)
+  : cmSPDXNonElementBase(CORE_POSITIVE_INTEGER_RANGE)
+  , BeginIntegerRange(beingIntegerRange)
+  , EndIntegerRange(endIntegerRange)
+{
+}
+
+Json::Value cmSPDXPositiveIntegerRange::toJsonLD() const
+{
+  auto obj = cmSPDXNonElementBase::toJsonLD();
+  obj["type"] = "PositiveIntegerRange";
+  obj["beginIntegerRange"] = BeginIntegerRange;
+  obj["endIntegerRange"] = EndIntegerRange;
+  return obj;
+}
+
+// SPDX Core Element Classes, Abstract
+
+cmSPDXElement::cmSPDXElement(SPDXTypeId id,
+                             cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXSerializationBase(id)
+  , CreationInfo(creationInfo)
+{
+}
+
+Json::Value cmSPDXElement::toJsonLD() const
+{
+  Json::Value obj(Json::objectValue);
+  addOptionalSPDXValue(obj, "comment", Comment);
+  obj["creationInfo"] = CreationInfo.toJsonLD();
+  addOptionalSPDXValue(obj, "description", Description);
+  addOptionalSPDXValue(obj, "extension", Extension);
+  addOptionalSPDXValue(obj, "externalIdentifier", ExternalIdentifier);
+  addOptionalSPDXValue(obj, "externalRef", ExternalRef);
+  addOptionalSPDXValue(obj, "name", Name);
+  obj["spdxId"] = NodeId;
+  addOptionalSPDXValue(obj, "summary", Summary);
+  addOptionalSPDXValue(obj, "verifiedUsing", VerifiedUsing);
+  return obj;
+}
+
+cmSPDXArtifact::cmSPDXArtifact(SPDXTypeId id,
+                               cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXElement(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXArtifact::toJsonLD() const
+{
+  auto obj = cmSPDXElement::toJsonLD();
+  addOptionalSPDXValue(obj, "builtTime", BuiltTime);
+  addOptionalSPDXValue(obj, "originateBy", OriginatedBy);
+  addOptionalSPDXValue(obj, "releaseTime", ReleaseTime);
+  addOptionalSPDXValue(obj, "standardName", StandardName);
+  addOptionalSPDXValue(obj, "suppliedBy", SuppliedBy);
+  addOptionalSPDXValue(obj, "supportType", SupportType);
+  addOptionalSPDXValue(obj, "validUntilTime", ValidUntilTime);
+  return obj;
+}
+
+cmSPDXElementCollection::cmSPDXElementCollection(
+  SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXElement(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXElementCollection::toJsonLD() const
+{
+  auto obj = cmSPDXElement::toJsonLD();
+  addOptionalSPDXValue(obj, "element", Element);
+  addOptionalSPDXValue(obj, "profileConformance", ProfileConformance);
+  addOptionalSPDXValue(obj, "rootElement", RootElement);
+  return obj;
+}
+
+// SPDX Implicit Core Element Classes, Abstract
+
+// Nominally an inheritable class, but adds nothing to Element
+using cmSPDXAgentAbstract = cmSPDXElement;
+
+cmSPDXBundleAbstract::cmSPDXBundleAbstract(
+  SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXElementCollection(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXBundleAbstract::toJsonLD() const
+{
+  auto obj = cmSPDXElementCollection::toJsonLD();
+  obj["context"] = Context;
+  return obj;
+}
+
+// Nominally an inheritable class, but adds nothing to Bundle
+using cmSPDXBomAbstract = cmSPDXBundleAbstract;
+
+cmSPDXRelationshipAbstract::cmSPDXRelationshipAbstract(
+  SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXElement(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXRelationshipAbstract::toJsonLD() const
+{
+  auto obj = cmSPDXElement::toJsonLD();
+  addOptionalSPDXValue(obj, "completeness", Completeness);
+  addOptionalSPDXValue(obj, "endTime", EndTime);
+  obj["from"] = From.toJsonLD();
+  obj["relationshipType"] = RelationshipType.toJsonLD();
+  addOptionalSPDXValue(obj, "startTime", StartTime);
+  addVectorSPDXValue(obj, "to", To);
+  return obj;
+}
+
+// SPDX Core Element Classes, Concrete
+
+cmSPDXAgent::cmSPDXAgent(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXAgentAbstract(CORE_AGENT, creationInfo)
+{
+}
+
+Json::Value cmSPDXAgent::toJsonLD() const
+{
+  auto obj = cmSPDXAgentAbstract::toJsonLD();
+  obj["type"] = "Agent";
+  return obj;
+}
+
+cmSPDXAnnotation::cmSPDXAnnotation(cmSPDXCreationInfo const& creationInfo,
+                                   cmSPDXIdentifierReference subject)
+  : cmSPDXElement(CORE_ANNOTATION, creationInfo)
+  , Subject(std::move(subject))
+{
+}
+
+Json::Value cmSPDXAnnotation::toJsonLD() const
+{
+  auto obj = cmSPDXElement::toJsonLD();
+  obj["type"] = "Annotation";
+  obj["annotationType"] = AnnotationType.toJsonLD();
+  addOptionalSPDXValue(obj, "contentType", ContentType);
+  addOptionalSPDXValue(obj, "statement", Statement);
+  obj["subject"] = Subject.toJsonLD();
+  return obj;
+}
+
+cmSPDXBom::cmSPDXBom(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXBomAbstract(CORE_BOM, creationInfo)
+{
+}
+
+Json::Value cmSPDXBom::toJsonLD() const
+{
+  auto obj = cmSPDXBomAbstract::toJsonLD();
+  obj["type"] = "Bom";
+  return obj;
+}
+
+cmSPDXBundle::cmSPDXBundle(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXBundleAbstract(CORE_BUNDLE, creationInfo)
+{
+}
+
+Json::Value cmSPDXBundle::toJsonLD() const
+{
+  auto obj = cmSPDXBundleAbstract::toJsonLD();
+  obj["type"] = "Bundle";
+  return obj;
+}
+
+cmSPDXIndividualElement::cmSPDXIndividualElement(
+  cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXElement(CORE_INDIVIDUAL_ELEMENT, creationInfo)
+{
+}
+
+Json::Value cmSPDXIndividualElement::toJsonLD() const
+{
+  auto obj = cmSPDXElement::toJsonLD();
+  obj["type"] = "IndividualElement";
+  return obj;
+}
+
+cmSPDXLifecycleScopedRelationship::cmSPDXLifecycleScopedRelationship(
+  cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXRelationshipAbstract(CORE_LIFECYCLE_SCOPED_RELATIONSHIP,
+                               creationInfo)
+{
+}
+
+Json::Value cmSPDXLifecycleScopedRelationship::toJsonLD() const
+{
+  auto obj = cmSPDXRelationshipAbstract::toJsonLD();
+  obj["type"] = "LifecycleScopedRelationship";
+  addOptionalSPDXValue(obj, "scope", Scope);
+  return obj;
+}
+
+cmSPDXOrganization::cmSPDXOrganization(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXAgentAbstract(CORE_ORGANIZATION, creationInfo)
+{
+}
+
+Json::Value cmSPDXOrganization::toJsonLD() const
+{
+  auto obj = cmSPDXAgentAbstract::toJsonLD();
+  obj["type"] = "Organization";
+  return obj;
+}
+
+cmSPDXPerson::cmSPDXPerson(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXAgentAbstract(CORE_PERSON, creationInfo)
+{
+}
+
+Json::Value cmSPDXPerson::toJsonLD() const
+{
+  auto obj = cmSPDXAgentAbstract::toJsonLD();
+  obj["type"] = "Person";
+  return obj;
+}
+
+cmSPDXRelationship::cmSPDXRelationship(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXRelationshipAbstract(CORE_RELATIONSHIP, creationInfo)
+{
+}
+
+Json::Value cmSPDXRelationship::toJsonLD() const
+{
+  auto obj = cmSPDXRelationshipAbstract::toJsonLD();
+  obj["type"] = "Relationship";
+  return obj;
+}
+
+cmSPDXSoftwareAgent::cmSPDXSoftwareAgent(
+  cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXAgentAbstract(CORE_SOFTWARE_AGENT, creationInfo)
+{
+}
+
+Json::Value cmSPDXSoftwareAgent::toJsonLD() const
+{
+  auto obj = cmSPDXAgentAbstract::toJsonLD();
+  obj["type"] = "SoftwareAgent";
+  return obj;
+}
+
+cmSPDXSpdxDocument::cmSPDXSpdxDocument(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXElementCollection(CORE_SPDX_DOCUMENT, creationInfo)
+{
+}
+
+Json::Value cmSPDXSpdxDocument::toJsonLD() const
+{
+  auto obj = cmSPDXElementCollection::toJsonLD();
+  obj["type"] = "SpdxDocument";
+  addOptionalSPDXValue(obj, "dataLicense", DataLicense);
+  addOptionalSPDXValue(obj, "externalMap", ExternalMap);
+  addOptionalSPDXValue(obj, "namespaceMap", NamespaceMap);
+  return obj;
+}
+
+cmSPDXTool::cmSPDXTool(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXElement(CORE_TOOL, creationInfo)
+{
+}
+
+Json::Value cmSPDXTool::toJsonLD() const
+{
+  auto obj = cmSPDXElement::toJsonLD();
+  obj["type"] = "Tool";
+  return obj;
+}
+
+// SPDX Software Enums
+
+cmSPDXContentIdentifierType::cmSPDXContentIdentifierType(
+  cmSPDXContentIdentifierTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXContentIdentifierType::toJsonLD() const
+{
+  switch (TypeId) {
+    case GITOID:
+      return "gitoid";
+    case SWHID:
+      return "swhid";
+    default:
+      return "INVALID_CONTENT_IDENTIFIER_TYPE_ID";
+  }
+}
+
+cmSPDXFileKindType::cmSPDXFileKindType(cmSPDXFileKindTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXFileKindType::toJsonLD() const
+{
+  switch (TypeId) {
+    case DIRECTORY:
+      return "directory";
+    case FILE:
+      return "file";
+    default:
+      return "INVALID_FILE_KIND_TYPE_ID";
+  }
+}
+
+cmSPDXSbomType::cmSPDXSbomType(cmSPDXSbomTypeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXSbomType::toJsonLD() const
+{
+  switch (TypeId) {
+    case ANALYZED:
+      return "analyzed";
+    case BUILD:
+      return "build";
+    case DEPLOYED:
+      return "deployed";
+    case DESIGN:
+      return "design";
+    case RUNTIME:
+      return "runtime";
+    case SOURCE:
+      return "source";
+    default:
+      return "INVALID_SBOM_TYPE_ID";
+  }
+}
+
+cmSPDXSoftwarePurpose::cmSPDXSoftwarePurpose(cmSPDXSoftwarePurposeId typeId)
+  : TypeId(typeId)
+{
+}
+
+Json::Value cmSPDXSoftwarePurpose::toJsonLD() const
+{
+  switch (TypeId) {
+    case APPLICATION:
+      return "application";
+    case ARCHIVE:
+      return "archive";
+    case BOM:
+      return "bom";
+    case CONFIGURATION:
+      return "configuration";
+    case CONTAINER:
+      return "container";
+    case DATA:
+      return "data";
+    case DEVICE:
+      return "device";
+    case DEVICE_DRIVER:
+      return "deviceDriver";
+    case DISK_IMAGE:
+      return "diskImage";
+    case DOCUMENTATION:
+      return "documentation";
+    case EVIDENCE:
+      return "evidence";
+    case EXECUTABLE:
+      return "executable";
+    case FILE:
+      return "file";
+    case FILESYSTEM_IMAGE:
+      return "filesystemImage";
+    case FIRMWARE:
+      return "firmware";
+    case FRAMEWORK:
+      return "framework";
+    case INSTALL:
+      return "install";
+    case LIBRARY:
+      return "library";
+    case MANIFEST:
+      return "manifest";
+    case MODEL:
+      return "model";
+    case MODULE:
+      return "module";
+    case OPERATING_SYSTEM:
+      return "operatingSystem";
+    case OTHER:
+      return "other";
+    case PATCH:
+      return "patch";
+    case PLATFORM:
+      return "platform";
+    case REQUIREMENT:
+      return "requirement";
+    case SOURCE:
+      return "source";
+    case SPECIFICATION:
+      return "specification";
+    case TEST:
+      return "test";
+    default:
+      return "INVALID_SOFTWARE_PURPOSE_ID";
+  }
+}
+
+// SPDX Software NonElement Classes, Concrete
+
+cmSPDXContentIdentifier::cmSPDXContentIdentifier()
+  : cmSPDXIntegrityMethod(SOFTWARE_CONTENT_IDENTIFIER)
+{
+}
+
+Json::Value cmSPDXContentIdentifier::toJsonLD() const
+{
+  auto obj = cmSPDXIntegrityMethod::toJsonLD();
+  obj["type"] = "ContentIdentifier";
+  obj["contentIdentifierType"] = ContentIdentifierType.toJsonLD();
+  obj["contentIdentifierValue"] = ContentIdentifierValue;
+  return obj;
+}
+
+// SPDX Software Element Classes, Abstract
+
+cmSPDXSoftwareArtifact::cmSPDXSoftwareArtifact(
+  SPDXTypeId id, cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXArtifact(id, creationInfo)
+{
+}
+
+Json::Value cmSPDXSoftwareArtifact::toJsonLD() const
+{
+  auto obj = cmSPDXArtifact::toJsonLD();
+  addOptionalSPDXValue(obj, "additionalPurpose", AdditionalPurpose);
+  addOptionalSPDXValue(obj, "attributionText", AttributionText);
+  addOptionalSPDXValue(obj, "contentIdentifier", ContentIdentifier);
+  addOptionalSPDXValue(obj, "copyrightText", CopyrightText);
+  addOptionalSPDXValue(obj, "primaryPurpose", PrimaryPurpose);
+  return obj;
+}
+
+// SPDX Software Element Classes, Concrete
+
+cmSPDXFile::cmSPDXFile(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXSoftwareArtifact(SOFTWARE_FILE, creationInfo)
+{
+}
+
+Json::Value cmSPDXFile::toJsonLD() const
+{
+  auto obj = cmSPDXSoftwareArtifact::toJsonLD();
+  obj["type"] = "File";
+  addOptionalSPDXValue(obj, "contentType", ContentType);
+  addOptionalSPDXValue(obj, "fileKind", FileKind);
+  return obj;
+}
+
+cmSPDXPackage::cmSPDXPackage(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXSoftwareArtifact(SOFTWARE_PACKAGE, creationInfo)
+{
+}
+
+Json::Value cmSPDXPackage::toJsonLD() const
+{
+  auto obj = cmSPDXSoftwareArtifact::toJsonLD();
+  obj["type"] = "Package";
+  addOptionalSPDXValue(obj, "downloadLocation", DownloadLocation);
+  addOptionalSPDXValue(obj, "homePage", HomePage);
+  addOptionalSPDXValue(obj, "packageUrl", PackageUrl);
+  addOptionalSPDXValue(obj, "packageVersion", PackageVersion);
+  addOptionalSPDXValue(obj, "sourceInfo", SourceInfo);
+  return obj;
+}
+
+cmSPDXSbom::cmSPDXSbom(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXBomAbstract(SOFTWARE_SBOM, creationInfo)
+{
+}
+
+Json::Value cmSPDXSbom::toJsonLD() const
+{
+  auto obj = cmSPDXBomAbstract::toJsonLD();
+  obj["type"] = "Sbom";
+  addOptionalSPDXValue(obj, "sbomType", SbomType);
+  return obj;
+}
+
+cmSPDXSnippet::cmSPDXSnippet(cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXSoftwareArtifact(SOFTWARE_SNIPPET, creationInfo)
+{
+}
+
+Json::Value cmSPDXSnippet::toJsonLD() const
+{
+  auto obj = cmSPDXSoftwareArtifact::toJsonLD();
+  obj["type"] = "Snippet";
+  addOptionalSPDXValue(obj, "byteRange", ByteRange);
+  addOptionalSPDXValue(obj, "lineRange", LineRange);
+  obj["snippetFromFile"] = SnippetFromFile.toJsonLD();
+  return obj;
+}
+
+// SPDX SimpleLicensing Element Classes, Concrete
+
+cmSPDXLicenseExpression::cmSPDXLicenseExpression(
+  cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXAnyLicenseInfo(SIMPLE_LICENSING_LICENSE_EXPRESSION, creationInfo)
+{
+}
+
+Json::Value cmSPDXLicenseExpression::toJsonLD() const
+{
+  auto obj = cmSPDXAnyLicenseInfo::toJsonLD();
+  obj["type"] = "LicenseExpression";
+  addOptionalSPDXValue(obj, "customIdToUri", CustomIdToUri);
+  obj["licenseExpression"] = LicenseExpression;
+  addOptionalSPDXValue(obj, "licenseListVersion", LicenseListVersion);
+  return obj;
+}
+
+cmSPDXSimpleLicensingText::cmSPDXSimpleLicensingText(
+  cmSPDXCreationInfo const& creationInfo)
+  : cmSPDXElement(SIMPLE_LICENSING_SIMPLE_LICENSING_TEXT, creationInfo)
+{
+}
+
+Json::Value cmSPDXSimpleLicensingText::toJsonLD() const
+{
+  auto obj = cmSPDXElement::toJsonLD();
+  obj["type"] = "SimpleLicensingText";
+  obj["licenseText"] = LicenseText;
+  return obj;
+}
+
+// Graph Manipulation
+
+#define X_SPDX(classtype, enumid, member, camel)                              \
+  template <>                                                                 \
+  cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId<classtype>()            \
+  {                                                                           \
+    return cmSPDXSerializationBase::enumid;                                   \
+  }                                                                           \
+                                                                              \
+  template <>                                                                 \
+  std::string cmSPDXGetTypeName<classtype>()                                  \
+  {                                                                           \
+    return #camel;                                                            \
+  }                                                                           \
+                                                                              \
+  cmSPDXObject::cmSPDXObject(classtype val)                                   \
+    : member(std::move(val)) {};                                              \
+                                                                              \
+  void cmSPDXObject::get(classtype** ptr)                                     \
+  {                                                                           \
+    *ptr = SerializationBase.getTypeId() == cmSPDXSerializationBase::enumid   \
+      ? &member                                                               \
+      : nullptr;                                                              \
+  }
+#include "cmSPDXTypes.def"
+
+cmSPDXObject::cmSPDXObject()
+  : IdentifierReference("UNINITIALIZED_SPDX_OBJECT")
+{
+}
+
+cmSPDXObject::cmSPDXObject(cmSPDXObject const& other)
+{
+  switch (other.SerializationBase.getTypeId()) {
+#define X_SPDX(classtype, enumid, member, camel)                              \
+  case cmSPDXSerializationBase::enumid:                                       \
+    new (&member) classtype(other.member);                                    \
+    break;
+#include "cmSPDXTypes.def"
+    default:
+      new (&IdentifierReference)
+        cmSPDXIdentifierReference("UNINITIALIZED_SPDX_OBJECT");
+  }
+}
+
+cmSPDXObject::cmSPDXObject(cmSPDXObject&& other) noexcept
+{
+  switch (other.SerializationBase.getTypeId()) {
+#define X_SPDX(classtype, enumid, member, camel)                              \
+  case cmSPDXSerializationBase::enumid:                                       \
+    new (&member) classtype(std::move(other.member));                         \
+    break;
+#include "cmSPDXTypes.def"
+    default:
+      new (&IdentifierReference)
+        cmSPDXIdentifierReference("UNINITIALIZED_SPDX_OBJECT");
+  }
+}
+
+cmSPDXObject& cmSPDXObject::operator=(cmSPDXObject const& other)
+{
+  this->~cmSPDXObject();
+  new (this) cmSPDXObject(other);
+  return *this;
+}
+
+cmSPDXObject& cmSPDXObject::operator=(cmSPDXObject&& other) noexcept
+{
+  this->~cmSPDXObject();
+  new (this) cmSPDXObject(std::move(other));
+  return *this;
+}
+
+cmSPDXObject::~cmSPDXObject()
+{
+  switch (SerializationBase.getTypeId()) {
+#define X_SPDX(classtype, enumid, member, camel)                              \
+  case cmSPDXSerializationBase::enumid:                                       \
+    member.~classtype();                                                      \
+    break;
+#include "cmSPDXTypes.def"
+    default:
+      break;
+  }
+}
+
+Json::Value cmSPDXObject::toJsonLD() const
+{
+  switch (SerializationBase.getTypeId()) {
+#define X_SPDX(classtype, enumid, member, camel)                              \
+  case cmSPDXSerializationBase::enumid:                                       \
+    return member.toJsonLD();
+#include "cmSPDXTypes.def"
+    default:
+      return "INVALID_SPDX_OBJECT_TYPE_ID";
+  }
+}
+
+cmSPDXSimpleGraph::cmSPDXSimpleGraph(std::string iriBase,
+                                     cmSPDXCreationInfo creationInfo)
+  : IRIBase(std::move(iriBase))
+  , CreationInfo(&insert<cmSPDXCreationInfo>(std::move(creationInfo)))
+{
+}
+
+cmSPDXCreationInfo& cmSPDXSimpleGraph::getCreationInfo()
+{
+  return *CreationInfo;
+}
+
+Json::Value cmSPDXSimpleGraph::toJsonLD()
+{
+  Json::Value obj(Json::objectValue);
+  obj["@context"] = "https://spdx.org/rdf/3.0.1/spdx-context.jsonld";
+
+  auto& graph = obj["@graph"];
+  for (auto const& it : Graph) {
+    graph.append(it.second.toJsonLD());
+  }
+
+  return obj;
+}
diff --git a/Source/cmSPDXSerializer.h b/Source/cmSPDXSerializer.h
new file mode 100644
index 0000000..65bf214
--- /dev/null
+++ b/Source/cmSPDXSerializer.h
@@ -0,0 +1,1008 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include <array>
+#include <cstddef>
+#include <map>
+#include <new>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/type_traits>
+
+#include <cm3p/json/value.h>
+
+#include "cmStringAlgorithms.h"
+
+// Base Class
+
+struct cmSPDXSerializationBase
+{
+  enum SPDXTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+
+#define X_SPDX(classtype, enumid, title, camel) enumid,
+#include "cmSPDXTypes.def"
+
+    SPDX_TYPE_ID_MAX,
+  };
+
+  SPDXTypeId getTypeId() const;
+
+  std::string NodeId;
+
+protected:
+  cmSPDXSerializationBase(SPDXTypeId id);
+  cmSPDXSerializationBase(SPDXTypeId id, std::string nodeId);
+
+private:
+  SPDXTypeId TypeId;
+};
+
+// Convenience Classes
+
+struct cmSPDXIdentifierReference : cmSPDXSerializationBase
+{
+  cmSPDXIdentifierReference();
+  cmSPDXIdentifierReference(cmSPDXSerializationBase const& ref);
+  cmSPDXIdentifierReference(std::string const& ref);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXNonElementBase : cmSPDXSerializationBase
+{
+protected:
+  cmSPDXNonElementBase(SPDXTypeId id);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Core Data Types
+
+// Nominally these are supposed to be validated strings
+using cmSPDXDateTime = std::string;
+using cmSPDXMediaType = std::string;
+using cmSPDXSemVer = std::string;
+
+// SPDX Core Enums
+
+struct cmSPDXAnnotationType
+{
+  enum cmSPDXAnnotationTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    OTHER,
+    REVIEW,
+  };
+
+  cmSPDXAnnotationTypeId TypeId;
+
+  cmSPDXAnnotationType(cmSPDXAnnotationTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalIdentifierType
+{
+  enum cmSPDXExternalIdentifierTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    CPE22,
+    CPE23,
+    CVE,
+    EMAIL,
+    GITOID,
+    OTHER,
+    PACKAGE_URL,
+    SECURITY_OTHER,
+    SWHID,
+    SWID,
+    URL_SCHEME,
+  };
+
+  cmSPDXExternalIdentifierTypeId TypeId;
+
+  cmSPDXExternalIdentifierType(
+    cmSPDXExternalIdentifierTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalRefType
+{
+  enum cmSPDXExternalRefTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    ALT_DOWNLOAD_LOCATION,
+    ALT_WEB_PAGE,
+    BINARY_ARTIFACT,
+    BOWER,
+    BUILD_META,
+    BUILD_SYSTEM,
+    CERTIFICATION_REPORT,
+    CHAT,
+    COMPONENT_ANALYSIS_REPORT,
+    CWE,
+    DOCUMENTATION,
+    DYNAMIC_ANALYSIS_REPORT,
+    EOL_NOTICE,
+    EXPORT_CONTROL_ASSESSMENT,
+    FUNDING,
+    ISSUE_TRACKER,
+    LICENSE,
+    MAILING_LIST,
+    MAVEN_CENTRAL,
+    METRICS,
+    NPM,
+    NUGET,
+    OTHER,
+    PRIVACY_ASSESSMENT,
+    PRODUCT_METADATA,
+    PURCHASE_ORDER,
+    QUALITY_ASSESSMENT_REPORT,
+    RELEASE_HISTORY,
+    RELEASE_NOTES,
+    RISK_ASSESSMENT,
+    RUNTIME_ANALYSIS_REPORT,
+    SECURE_SOFTWARE_ATTESTATION,
+    SECURITY_ADVERSARY_MODEL,
+    SECURITY_ADVISORY,
+    SECURITY_FIX,
+    SECURITY_OTHER,
+    SECURITY_PEN_TEST_REPORT,
+    SECURITY_POLICY,
+    SECURITY_THREAT_MODEL,
+    SOCIAL_MEDIA,
+    SOURCE_ARTIFACT,
+    STATIC_ANALYSIS_REPORT,
+    SUPPORT,
+    VCS,
+    VULNERABILITY_DISCLOSURE_REPORT,
+    VULNERABILITY_EXPLOITABILITY_ASSESSMENT,
+  };
+
+  cmSPDXExternalRefTypeId TypeId;
+
+  cmSPDXExternalRefType(cmSPDXExternalRefTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXHashAlgorithm
+{
+  enum cmSPDXHashAlgorithmId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    ADLER32,
+    BLAKE2B256,
+    BLAKE2B384,
+    BLAKE2B512,
+    BLAKE3,
+    CRYSTALS_DILITHIUM,
+    CRYSTALS_KYBER,
+    FALCON,
+    MD2,
+    MD4,
+    MD5,
+    MD6,
+    OTHER,
+    SHA1,
+    SHA224,
+    SHA256,
+    SHA384,
+    SHA3_224,
+    SHA3_256,
+    SHA3_384,
+    SHA3_512,
+    SHA512,
+  };
+
+  cmSPDXHashAlgorithmId TypeId;
+
+  cmSPDXHashAlgorithm(cmSPDXHashAlgorithmId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXLifecycleScopeType
+{
+  enum cmSPDXLifecycleScopeTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    BUILD,
+    DESIGN,
+    DEVELOPMENT,
+    OTHER,
+    RUNTIME,
+    TEST,
+  };
+
+  cmSPDXLifecycleScopeTypeId TypeId;
+
+  cmSPDXLifecycleScopeType(cmSPDXLifecycleScopeTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXProfileIdentifierType
+{
+  enum cmSPDXProfileIdentifierTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    AI,
+    BUILD,
+    CORE,
+    DATASET,
+    EXPANDED_LICENSING,
+    EXTENSION,
+    LITE,
+    SECURITY,
+    SIMPLE_LICENSING,
+    SOFTWARE,
+  };
+
+  cmSPDXProfileIdentifierTypeId TypeId;
+
+  cmSPDXProfileIdentifierType(cmSPDXProfileIdentifierTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXRelationshipCompletenessType
+{
+  enum cmSPDXRelationshipCompletenessTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    COMPLETE,
+    INCOMPLETE,
+    NO_ASSERTION,
+  };
+
+  cmSPDXRelationshipCompletenessTypeId TypeId;
+
+  cmSPDXRelationshipCompletenessType(
+    cmSPDXRelationshipCompletenessTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXRelationshipType
+{
+  enum cmSPDXRelationshipTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    AFFECTS,
+    AMENDED_BY,
+    ANCESTOR_OF,
+    AVAILABLE_FROM,
+    CONFIGURES,
+    CONTAINS,
+    COORDINATED_BY,
+    COPIED_TO,
+    DELEGATED_TO,
+    DEPENDS_ON,
+    DESCENDANT_OF,
+    DESCRIBES,
+    DOES_NOT_AFFECT,
+    EXPANDS_TO,
+    EXPLOIT_CREATED_BY,
+    FIXED_BY,
+    FIXED_IN,
+    FOUND_BY,
+    GENERATES,
+    HAS_ADDED_FILE,
+    HAS_ASSESSMENT_FOR,
+    HAS_ASSOCIATED_VULNERABILITY,
+    HAS_CONCLUDED_LICENSE,
+    HAS_DATA_FILE,
+    HAS_DECLARED_LICENSE,
+    HAS_DELETED_FILE,
+    HAS_DEPENDENCY_MANIFEST,
+    HAS_DISTRIBUTION_ARTIFACT,
+    HAS_DOCUMENTATION,
+    HAS_DYNAMIC_LINK,
+    HAS_EVIDENCE,
+    HAS_EXAMPLE,
+    HAS_HOST,
+    HAS_INPUT,
+    HAS_METADATA,
+    HAS_OPTIONAL_COMPONENT,
+    HAS_OPTIONAL_DEPENDENCY,
+    HAS_OUTPUT,
+    HAS_PREREQUISITE,
+    HAS_PROVIDED_DEPENDENCY,
+    HAS_REQUIREMENT,
+    HAS_SPECIFICATION,
+    HAS_STATIC_LINK,
+    HAS_TEST,
+    HAS_TEST_CASE,
+    HAS_VARIANT,
+    INVOKED_BY,
+    MODIFIED_BY,
+    OTHER,
+    PACKAGED_BY,
+    PATCHED_BY,
+    PUBLISHED_BY,
+    REPORTED_BY,
+    REPUBLISHED_BY,
+    SERIALIZED_IN_ARTIFACT,
+    TESTED_ON,
+    TRAINED_ON,
+    UNDER_INVESTIGATION_FOR,
+    USES_TOOL,
+  };
+
+  cmSPDXRelationshipTypeId TypeId;
+
+  cmSPDXRelationshipType(cmSPDXRelationshipTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSupportType
+{
+  enum cmSPDXSupportTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    DEPLOYED,
+    DEVELOPMENT,
+    END_OF_SUPPORT,
+    LIMITED_SUPPORT,
+    NO_ASSERTION,
+    NO_SUPPORT,
+    SUPPORT,
+  };
+
+  cmSPDXSupportTypeId TypeId;
+
+  cmSPDXSupportType(cmSPDXSupportTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Core NonElement Classes, Abstract
+
+struct cmSPDXIntegrityMethod : cmSPDXNonElementBase
+{
+
+  cm::optional<std::string> Comment;
+
+protected:
+  cmSPDXIntegrityMethod(SPDXTypeId id);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Core NonElement Classes, Concrete
+
+struct cmSPDXCreationInfo : cmSPDXNonElementBase
+{
+  cm::optional<std::string> Comment;
+  cmSPDXDateTime Created;
+  std::vector<cmSPDXIdentifierReference> CreatedBy;
+  cm::optional<std::vector<cmSPDXIdentifierReference>> CreatedUsing;
+
+  cmSPDXCreationInfo();
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXDictionaryEntry : cmSPDXNonElementBase
+{
+  std::string Key;
+  cm::optional<std::string> Value;
+
+  cmSPDXDictionaryEntry();
+  cmSPDXDictionaryEntry(std::string key);
+  cmSPDXDictionaryEntry(std::string key, std::string val);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalIdentifier : cmSPDXNonElementBase
+{
+  cm::optional<std::string> Comment;
+  cmSPDXExternalIdentifierType ExternalIdentifierType;
+  std::string Identifier;
+  cm::optional<std::vector<std::string>> IdentifierLocator;
+  cm::optional<std::string> IssuingAuthority;
+
+  cmSPDXExternalIdentifier();
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalMap : cmSPDXNonElementBase
+{
+  cm::optional<cmSPDXIdentifierReference> DefiningArtifact;
+  std::string ExternalSpdxId;
+  cm::optional<std::string> LocationHint;
+  cm::optional<std::vector<cmSPDXIdentifierReference>> IntegrityMethod;
+
+  cmSPDXExternalMap();
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXExternalRef : cmSPDXNonElementBase
+{
+  cm::optional<std::string> Comment;
+  cm::optional<cmSPDXMediaType> ContentType;
+  cm::optional<cmSPDXExternalRefType> ExternalRefType;
+  cm::optional<std::vector<std::string>> Locator;
+
+  cmSPDXExternalRef();
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXHash : cmSPDXIntegrityMethod
+{
+  cmSPDXHashAlgorithm Algorithm;
+  std::string HashValue;
+
+  cmSPDXHash();
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXNamespaceMap : cmSPDXNonElementBase
+{
+  std::string Namespace;
+  std::string Prefix;
+
+  cmSPDXNamespaceMap();
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXPackageVerificationCode : cmSPDXIntegrityMethod
+{
+  cmSPDXHashAlgorithm Algorithm;
+  std::string HashValue;
+  cm::optional<std::vector<std::string>> PackageVerificationCodeExcludedFile;
+
+  cmSPDXPackageVerificationCode();
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXPositiveIntegerRange : cmSPDXNonElementBase
+{
+  unsigned int BeginIntegerRange;
+  unsigned int EndIntegerRange;
+
+  cmSPDXPositiveIntegerRange(unsigned int beingIntegerRange = 0,
+                             unsigned int endIntegerRange = 0);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Core Element Classes, Abstract
+
+struct cmSPDXElement : cmSPDXSerializationBase
+{
+  cm::optional<std::string> Comment;
+  cmSPDXIdentifierReference CreationInfo;
+  cm::optional<std::string> Description;
+  cm::optional<std::vector<cmSPDXIdentifierReference>> Extension;
+  cm::optional<std::vector<cmSPDXIdentifierReference>> ExternalIdentifier;
+  cm::optional<std::vector<cmSPDXIdentifierReference>> ExternalRef;
+  cm::optional<std::string> Name;
+  // SpdxId is the NodeId
+  cm::optional<std::string> Summary;
+  cm::optional<std::vector<cmSPDXIdentifierReference>> VerifiedUsing;
+
+protected:
+  cmSPDXElement(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXArtifact : cmSPDXElement
+{
+  cm::optional<cmSPDXDateTime> BuiltTime;
+  cm::optional<std::vector<cmSPDXIdentifierReference>> OriginatedBy;
+  cm::optional<cmSPDXDateTime> ReleaseTime;
+  cm::optional<std::vector<std::string>> StandardName;
+  cm::optional<cmSPDXIdentifierReference> SuppliedBy;
+  cm::optional<std::vector<cmSPDXSupportType>> SupportType;
+  cm::optional<cmSPDXDateTime> ValidUntilTime;
+
+protected:
+  cmSPDXArtifact(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXElementCollection : cmSPDXElement
+{
+  cm::optional<std::vector<cmSPDXIdentifierReference>> Element;
+  cm::optional<std::vector<cmSPDXProfileIdentifierType>> ProfileConformance;
+  cm::optional<std::vector<cmSPDXIdentifierReference>> RootElement;
+
+protected:
+  cmSPDXElementCollection(SPDXTypeId id,
+                          cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Implicit Core Element Classes, Abstract
+
+// Nominally an inheritable class, but adds nothing to Element
+using cmSPDXAgentAbstract = cmSPDXElement;
+
+struct cmSPDXBundleAbstract : cmSPDXElementCollection
+{
+  std::string Context;
+
+protected:
+  cmSPDXBundleAbstract(SPDXTypeId id, cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+// Nominally an inheritable class, but adds nothing to Bundle
+using cmSPDXBomAbstract = cmSPDXBundleAbstract;
+
+struct cmSPDXRelationshipAbstract : cmSPDXElement
+{
+  cm::optional<cmSPDXRelationshipCompletenessType> Completeness;
+  cm::optional<cmSPDXDateTime> EndTime;
+  cmSPDXIdentifierReference From;
+  cmSPDXRelationshipType RelationshipType;
+  cm::optional<cmSPDXDateTime> StartTime;
+  std::vector<cmSPDXIdentifierReference> To;
+
+protected:
+  cmSPDXRelationshipAbstract(SPDXTypeId id,
+                             cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Core Element Classes, Concrete
+
+struct cmSPDXAgent : cmSPDXAgentAbstract
+{
+  cmSPDXAgent(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXAnnotation : cmSPDXElement
+{
+  cmSPDXAnnotationType AnnotationType;
+  cm::optional<cmSPDXMediaType> ContentType;
+  cm::optional<std::string> Statement;
+  cmSPDXIdentifierReference Subject;
+
+  cmSPDXAnnotation(cmSPDXCreationInfo const& creationInfo,
+                   cmSPDXIdentifierReference subject = {});
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXBom : cmSPDXBomAbstract
+{
+  cmSPDXBom(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXBundle : cmSPDXBundleAbstract
+{
+  cmSPDXBundle(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXIndividualElement : cmSPDXElement
+{
+  cmSPDXIndividualElement(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXLifecycleScopedRelationship : cmSPDXRelationshipAbstract
+{
+  cm::optional<cmSPDXLifecycleScopeType> Scope;
+
+  cmSPDXLifecycleScopedRelationship(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXOrganization : cmSPDXAgentAbstract
+{
+  cmSPDXOrganization(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXPerson : cmSPDXAgentAbstract
+{
+  cmSPDXPerson(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXRelationship : cmSPDXRelationshipAbstract
+{
+  cmSPDXRelationship(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSoftwareAgent : cmSPDXAgentAbstract
+{
+  cmSPDXSoftwareAgent(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSpdxDocument : cmSPDXElementCollection
+{
+  cm::optional<cmSPDXIdentifierReference> DataLicense;
+  cm::optional<cmSPDXIdentifierReference> ExternalMap;
+  cm::optional<cmSPDXIdentifierReference> NamespaceMap;
+
+  cmSPDXSpdxDocument(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXTool : cmSPDXElement
+{
+  cmSPDXTool(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Software Enums
+
+struct cmSPDXContentIdentifierType
+{
+  enum cmSPDXContentIdentifierTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    GITOID,
+    SWHID,
+  };
+
+  cmSPDXContentIdentifierTypeId TypeId;
+
+  cmSPDXContentIdentifierType(cmSPDXContentIdentifierTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXFileKindType
+{
+  enum cmSPDXFileKindTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    DIRECTORY,
+    FILE,
+  };
+
+  cmSPDXFileKindTypeId TypeId;
+
+  cmSPDXFileKindType(cmSPDXFileKindTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSbomType
+{
+  enum cmSPDXSbomTypeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    ANALYZED,
+    BUILD,
+    DEPLOYED,
+    DESIGN,
+    RUNTIME,
+    SOURCE,
+  };
+
+  cmSPDXSbomTypeId TypeId;
+
+  cmSPDXSbomType(cmSPDXSbomTypeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSoftwarePurpose
+{
+  enum cmSPDXSoftwarePurposeId
+  {
+    INVALID = -1,
+    NULL_ID = 0,
+    APPLICATION,
+    ARCHIVE,
+    BOM,
+    CONFIGURATION,
+    CONTAINER,
+    DATA,
+    DEVICE,
+    DEVICE_DRIVER,
+    DISK_IMAGE,
+    DOCUMENTATION,
+    EVIDENCE,
+    EXECUTABLE,
+    FILE,
+    FILESYSTEM_IMAGE,
+    FIRMWARE,
+    FRAMEWORK,
+    INSTALL,
+    LIBRARY,
+    MANIFEST,
+    MODEL,
+    MODULE,
+    OPERATING_SYSTEM,
+    OTHER,
+    PATCH,
+    PLATFORM,
+    REQUIREMENT,
+    SOURCE,
+    SPECIFICATION,
+    TEST,
+  };
+
+  cmSPDXSoftwarePurposeId TypeId;
+
+  cmSPDXSoftwarePurpose(cmSPDXSoftwarePurposeId typeId = NULL_ID);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Software NonElement Classes, Concrete
+
+struct cmSPDXContentIdentifier : cmSPDXIntegrityMethod
+{
+  cmSPDXContentIdentifierType ContentIdentifierType;
+  std::string ContentIdentifierValue;
+
+  cmSPDXContentIdentifier();
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Software Element Classes, Abstract
+
+struct cmSPDXSoftwareArtifact : cmSPDXArtifact
+{
+  cm::optional<std::vector<cmSPDXSoftwarePurpose>> AdditionalPurpose;
+  cm::optional<std::string> AttributionText;
+  cm::optional<cmSPDXIdentifierReference> ContentIdentifier;
+  cm::optional<std::string> CopyrightText;
+  cm::optional<cmSPDXSoftwarePurpose> PrimaryPurpose;
+
+protected:
+  cmSPDXSoftwareArtifact(SPDXTypeId id,
+                         cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX Software Element Classes, Concrete
+
+struct cmSPDXFile : cmSPDXSoftwareArtifact
+{
+  cm::optional<cmSPDXMediaType> ContentType;
+  cm::optional<cmSPDXFileKindType> FileKind;
+
+  cmSPDXFile(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXPackage : cmSPDXSoftwareArtifact
+{
+  cm::optional<std::string> DownloadLocation;
+  cm::optional<std::string> HomePage;
+  cm::optional<std::string> PackageUrl;
+  cm::optional<std::string> PackageVersion;
+  cm::optional<std::string> SourceInfo;
+
+  cmSPDXPackage(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSbom : cmSPDXBomAbstract
+{
+  cm::optional<std::vector<cmSPDXSbomType>> SbomType;
+
+  cmSPDXSbom(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSnippet : cmSPDXSoftwareArtifact
+{
+  cm::optional<cmSPDXIdentifierReference> ByteRange;
+  cm::optional<cmSPDXIdentifierReference> LineRange;
+  cmSPDXIdentifierReference SnippetFromFile;
+
+  cmSPDXSnippet(cmSPDXCreationInfo const& creationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+// SPDX SimpleLicensing Element Classes, Abstract
+
+// Nominally an inheritable class, but adds nothing to Element
+using cmSPDXAnyLicenseInfo = cmSPDXElement;
+
+// SPDX SimpleLicensing Element Classes, Concrete
+
+struct cmSPDXLicenseExpression : cmSPDXAnyLicenseInfo
+{
+  cm::optional<std::vector<cmSPDXIdentifierReference>> CustomIdToUri;
+  std::string LicenseExpression;
+  cm::optional<cmSPDXSemVer> LicenseListVersion;
+
+  cmSPDXLicenseExpression(cmSPDXCreationInfo const& CreationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+struct cmSPDXSimpleLicensingText : cmSPDXElement
+{
+  std::string LicenseText;
+
+  cmSPDXSimpleLicensingText(cmSPDXCreationInfo const& CreationInfo);
+
+  Json::Value toJsonLD() const;
+};
+
+// Graph Manipulation
+
+template <typename T>
+cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId();
+
+template <typename T>
+std::string cmSPDXGetTypeName();
+
+#define X_SPDX(classtype, enumid, member, camel)                              \
+  template <>                                                                 \
+  cmSPDXSerializationBase::SPDXTypeId cmSPDXGetTypeId<classtype>();           \
+                                                                              \
+  template <>                                                                 \
+  std::string cmSPDXGetTypeName<classtype>();
+#include "cmSPDXTypes.def"
+
+template <class T>
+struct cmSPDXTag
+{
+  using type = T;
+};
+
+union cmSPDXObject
+{
+
+  cmSPDXSerializationBase SerializationBase;
+
+  cmSPDXObject();
+  cmSPDXObject(cmSPDXObject const& other);
+  cmSPDXObject(cmSPDXObject&& other) noexcept;
+
+#define X_SPDX(classtype, enumid, member, camel)                              \
+  classtype member;                                                           \
+  cmSPDXObject(classtype val);                                                \
+                                                                              \
+  template <typename... Args>                                                 \
+  cmSPDXObject(cmSPDXTag<classtype>, Args&&... args)                          \
+  {                                                                           \
+    new (&member) classtype(std::forward<Args>(args)...);                     \
+  }
+#include "cmSPDXTypes.def"
+
+  cmSPDXObject& operator=(cmSPDXObject const& other);
+  cmSPDXObject& operator=(cmSPDXObject&& other) noexcept;
+
+  ~cmSPDXObject();
+
+  template <typename T>
+  T* get()
+  {
+    T* ptr;
+    get(&ptr);
+    return ptr;
+  }
+
+  Json::Value toJsonLD() const;
+
+private:
+#define X_SPDX(classtype, enumid, member, camel) void get(classtype** ptr);
+#include "cmSPDXTypes.def"
+};
+
+struct cmSPDXSimpleGraph
+{
+  cmSPDXSimpleGraph(std::string iriBase, cmSPDXCreationInfo creationInfo = {});
+
+  template <typename T, typename... Args>
+  cm::enable_if_t<std::is_base_of<cmSPDXElement, T>::value, T>& insert(
+    Args&&... args)
+  {
+    std::string nodeId = cmStrCat(IRIBase, IRICount++);
+    auto const& it =
+      Graph.emplace(std::piecewise_construct, std::forward_as_tuple(nodeId),
+                    std::forward_as_tuple(cmSPDXTag<T>{}, *CreationInfo,
+                                          std::forward<Args>(args)...));
+    auto& node = *it.first->second.template get<T>();
+    node.NodeId = std::move(nodeId);
+    return node;
+  }
+
+  cmSPDXCreationInfo& getCreationInfo();
+
+  template <typename T, typename... Args>
+  cm::enable_if_t<std::is_base_of<cmSPDXNonElementBase, T>::value, T>& insert(
+    Args&&... args)
+  {
+    std::size_t nodeCount = BlankCounts[cmSPDXGetTypeId<T>()]++;
+    std::string nodeId =
+      cmStrCat("_:", cmSPDXGetTypeName<T>(), "_", nodeCount);
+    auto const& it = Graph.emplace(
+      std::piecewise_construct, std::forward_as_tuple(nodeId),
+      std::forward_as_tuple(cmSPDXTag<T>{}, std::forward<Args>(args)...));
+    auto& node = *it.first->second.template get<T>();
+    node.NodeId = std::move(nodeId);
+    return node;
+  }
+
+  template <typename T>
+  T* get(std::string const& key)
+  {
+    auto it = Graph.find(key);
+    if (it == Graph.end()) {
+      return nullptr;
+    }
+    return it->second.get<T>();
+  }
+
+  template <typename T>
+  T* get(cmSPDXIdentifierReference const& key)
+  {
+    auto it = Graph.find(key.NodeId);
+    if (it == Graph.end()) {
+      return nullptr;
+    }
+    return it->second.get<T>();
+  }
+
+  Json::Value toJsonLD();
+
+private:
+  std::string IRIBase;
+  std::size_t IRICount{ 0 };
+  std::array<std::size_t, cmSPDXSerializationBase::SPDX_TYPE_ID_MAX>
+    BlankCounts{};
+
+  std::map<std::string, cmSPDXObject> Graph;
+  cmSPDXCreationInfo* CreationInfo;
+};
diff --git a/Source/cmSPDXTypes.def b/Source/cmSPDXTypes.def
new file mode 100644
index 0000000..88d8043
--- /dev/null
+++ b/Source/cmSPDXTypes.def
@@ -0,0 +1,54 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#ifndef X_SPDX
+#  define X_SPDX(classtype, enumid, member, camel)
+#endif
+
+// Convenience
+X_SPDX(cmSPDXIdentifierReference, CM_IDENTIFIER_REFERENCE, IdentifierReference,
+       identifierReference)
+
+// Core
+X_SPDX(cmSPDXAgent, CORE_AGENT, Agent, agent)
+X_SPDX(cmSPDXAnnotation, CORE_ANNOTATION, Annotation, annotation)
+X_SPDX(cmSPDXBom, CORE_BOM, Bom, bom)
+X_SPDX(cmSPDXBundle, CORE_BUNDLE, Bundle, bundle)
+X_SPDX(cmSPDXCreationInfo, CORE_CREATION_INFO, CreationInfo, creationInfo)
+X_SPDX(cmSPDXDictionaryEntry, CORE_DICTIONARY_ENTRY, DictionaryEntry,
+       dictionaryEntry)
+X_SPDX(cmSPDXExternalIdentifier, CORE_EXTERNAL_IDENTIFIER, ExternalIdentifier,
+       externalIdentifier)
+X_SPDX(cmSPDXExternalMap, CORE_EXTERNAL_MAP, ExternalMap, externalMap)
+X_SPDX(cmSPDXExternalRef, CORE_EXTERNAL_REF, ExternalRef, externalRef)
+X_SPDX(cmSPDXHash, CORE_HASH, Hash, hash)
+X_SPDX(cmSPDXIndividualElement, CORE_INDIVIDUAL_ELEMENT, IndividualElement,
+       individualElement)
+X_SPDX(cmSPDXLifecycleScopedRelationship, CORE_LIFECYCLE_SCOPED_RELATIONSHIP,
+       LifecycleScopedRelationship, lifecycleScopedRelationship)
+X_SPDX(cmSPDXNamespaceMap, CORE_NAMESPACE_MAP, NamespaceMap, namespaceMap)
+X_SPDX(cmSPDXOrganization, CORE_ORGANIZATION, Organization, organization)
+X_SPDX(cmSPDXPackageVerificationCode, CORE_PACKAGE_VERIFICATION_CODE,
+       PackageVerificationCode, packageVerificationCode)
+X_SPDX(cmSPDXPerson, CORE_PERSON, Person, person)
+X_SPDX(cmSPDXPositiveIntegerRange, CORE_POSITIVE_INTEGER_RANGE,
+       PositiveIntegerRange, positiveIntegerRange)
+X_SPDX(cmSPDXRelationship, CORE_RELATIONSHIP, Relationship, relationship)
+X_SPDX(cmSPDXSoftwareAgent, CORE_SOFTWARE_AGENT, SoftwareAgent, softwareAgent)
+X_SPDX(cmSPDXSpdxDocument, CORE_SPDX_DOCUMENT, SpdxDocument, spdxDocument)
+X_SPDX(cmSPDXTool, CORE_TOOL, Tool, tool)
+
+// Software
+X_SPDX(cmSPDXContentIdentifier, SOFTWARE_CONTENT_IDENTIFIER, ContentIdentifier,
+       contentIdentifier)
+X_SPDX(cmSPDXFile, SOFTWARE_FILE, File, file)
+X_SPDX(cmSPDXPackage, SOFTWARE_PACKAGE, Package, package)
+X_SPDX(cmSPDXSbom, SOFTWARE_SBOM, Sbom, sbom)
+X_SPDX(cmSPDXSnippet, SOFTWARE_SNIPPET, Snippet, snippet)
+
+// SimpleLicensing
+X_SPDX(cmSPDXLicenseExpression, SIMPLE_LICENSING_LICENSE_EXPRESSION,
+       LicenseExpression, licenseExpression)
+X_SPDX(cmSPDXSimpleLicensingText, SIMPLE_LICENSING_SIMPLE_LICENSING_TEXT,
+       SimpleLicensingText, simpleLicensingText)
+
+#undef X_SPDX
diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx
index e865bf6..0fa9d94 100644
--- a/Source/cmSetCommand.cxx
+++ b/Source/cmSetCommand.cxx
@@ -2,6 +2,14 @@
    file LICENSE.rst or https://cmake.org/licensing for details.  */
 #include "cmSetCommand.h"
 
+#include <algorithm>
+
+#include <cm/optional>
+#include <cm/string_view>
+#include <cmext/string_view>
+
+#include "cmArgumentParser.h"
+#include "cmArgumentParserTypes.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
 #include "cmMakefile.h"
@@ -22,8 +30,8 @@
     return false;
   }
 
-  // watch for ENV signatures
   auto const& variable = args[0]; // VAR is always first
+  // watch for ENV{} signature
   if (cmHasLiteralPrefix(variable, "ENV{") && variable.size() > 5) {
     // what is the variable name
     auto const& varName = variable.substr(4, variable.size() - 5);
@@ -58,6 +66,81 @@
     return true;
   }
 
+  // watch for CACHE{} signature
+  if (cmHasLiteralPrefix(variable, "CACHE{") && variable.size() > 7 &&
+      cmHasLiteralSuffix(variable, "}")) {
+    // what is the variable name
+    auto const& varName = variable.substr(6, variable.size() - 7);
+    // VALUE handling
+    auto valueArg = std::find(args.cbegin() + 1, args.cend(), "VALUE");
+    if (valueArg == args.cend()) {
+      status.SetError("Required argument 'VALUE' is missing.");
+      return false;
+    }
+    auto value = cmMakeRange(valueArg + 1, args.cend());
+    // Handle options
+    struct Arguments : public ArgumentParser::ParseResult
+    {
+      ArgumentParser::Continue validateTypeValue(cm::string_view type)
+      {
+        if (!cmState::StringToCacheEntryType(std::string{ type },
+                                             this->Type)) {
+          this->AddKeywordError("TYPE"_s,
+                                cmStrCat("Invalid value: ", type, '.'));
+        }
+        return ArgumentParser::Continue::No;
+      }
+      cmStateEnums::CacheEntryType Type = cmStateEnums::UNINITIALIZED;
+      cm::optional<ArgumentParser::NonEmpty<std::vector<std::string>>> Help;
+      bool Force = false;
+    };
+    static auto const optionsParser =
+      cmArgumentParser<Arguments>{}
+        .Bind("TYPE"_s, &Arguments::validateTypeValue)
+        .Bind("HELP"_s, &Arguments::Help)
+        .Bind("FORCE"_s, &Arguments::Force);
+    std::vector<std::string> unrecognizedArguments;
+    auto parsedArgs = optionsParser.Parse(
+      cmMakeRange(args.cbegin() + 1, valueArg), &unrecognizedArguments);
+    if (!unrecognizedArguments.empty()) {
+      status.SetError(cmStrCat("Called with unsupported argument(s): ",
+                               cmJoin(unrecognizedArguments, ",  "_s), '.'));
+      return false;
+    }
+    if (parsedArgs.MaybeReportError(status.GetMakefile())) {
+      return false;
+    }
+
+    // see if this is already in the cache
+    cmState* state = status.GetMakefile().GetState();
+    cmValue existingValue = state->GetCacheEntryValue(varName);
+    cmStateEnums::CacheEntryType existingType =
+      state->GetCacheEntryType(varName);
+    if (parsedArgs.Type == cmStateEnums::UNINITIALIZED) {
+      parsedArgs.Type = existingType == cmStateEnums::UNINITIALIZED
+        ? cmStateEnums::STRING
+        : existingType;
+    }
+    std::string help = parsedArgs.Help
+      ? cmJoin(*parsedArgs.Help, "")
+      : *state->GetCacheEntryProperty(varName, "HELPSTRING");
+    if (existingValue && existingType != cmStateEnums::UNINITIALIZED) {
+      // if the set is trying to CACHE the value but the value
+      // is already in the cache and the type is not internal
+      // then leave now without setting any definitions in the cache
+      // or the makefile
+      if (parsedArgs.Type != cmStateEnums::INTERNAL && !parsedArgs.Force) {
+        return true;
+      }
+    }
+
+    status.GetMakefile().AddCacheDefinition(
+      varName,
+      valueArg == args.cend() ? *existingValue : cmList::to_string(value),
+      help, parsedArgs.Type, parsedArgs.Force);
+    return true;
+  }
+
   // SET (VAR) // Removes the definition of VAR.
   if (args.size() == 1) {
     status.GetMakefile().RemoveDefinition(variable);
diff --git a/Source/cmSetSourceFilesPropertiesCommand.cxx b/Source/cmSetSourceFilesPropertiesCommand.cxx
index 98911c0..769efea 100644
--- a/Source/cmSetSourceFilesPropertiesCommand.cxx
+++ b/Source/cmSetSourceFilesPropertiesCommand.cxx
@@ -37,7 +37,7 @@
   };
 
   auto isAPropertyKeyword =
-    [](std::vector<std::string>::const_iterator const& arg_it) {
+    [](std::vector<std::string>::const_iterator arg_it) {
       return std::any_of(
         std::begin(prop_names), std::end(prop_names),
         [&arg_it](cm::string_view prop_name) { return *arg_it == prop_name; });
diff --git a/Source/cmStack.h b/Source/cmStack.h
new file mode 100644
index 0000000..1c11090
--- /dev/null
+++ b/Source/cmStack.h
@@ -0,0 +1,61 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#pragma once
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <memory>
+#include <type_traits>
+
+enum class cmStackType
+{
+  Const,
+  Mutable,
+};
+
+template <typename T, cmStackType Mutable>
+struct cmStackEntry;
+
+/** Base class template for CRTP to represent a stack of values.
+    Copies of the stack <i>share data</i>; mutating data on one copy will
+    change the data on <i>all</i> copies.  */
+template <typename T, typename Stack,
+          cmStackType Mutable = cmStackType::Mutable>
+class cmStack
+{
+  using Entry = cmStackEntry<T, Mutable>;
+
+  std::shared_ptr<Entry const> TopEntry;
+
+public:
+  /** Default-construct an empty stack.  */
+  cmStack();
+
+  /** Get a stack with the given call context added to the top.  */
+  Stack Push(T value) const;
+
+  /** Get a stack with the top level removed.
+      May not be called until after a matching Push.  */
+  Stack Pop() const;
+
+  /** Get the value at the top of the stack.
+      This may be called only if Empty() would return false.  */
+  T const& Top() const;
+  template <bool E = (Mutable == cmStackType::Mutable)>
+  typename std::enable_if<E, T>::type& Top();
+
+  /** Return true if this stack is empty.  */
+  bool Empty() const;
+
+protected:
+  using Base = cmStack<T, Stack, Mutable>;
+
+  cmStack(std::shared_ptr<Entry const> parent, T value);
+  cmStack(std::shared_ptr<Entry const> top);
+};
+
+/** Specialization of cmStack for CRTP to represent a stack of constant values.
+    Provide value semantics, but use efficient reference-counting underneath
+    to avoid copies.  */
+template <typename T, typename Stack>
+using cmConstStack = cmStack<T const, Stack, cmStackType::Const>;
diff --git a/Source/cmStack.tcc b/Source/cmStack.tcc
new file mode 100644
index 0000000..210833b
--- /dev/null
+++ b/Source/cmStack.tcc
@@ -0,0 +1,85 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+#include <cassert>
+#include <memory>
+#include <utility>
+
+template <typename T>
+struct cmStackEntry<T, cmStackType::Mutable>
+{
+  cmStackEntry(std::shared_ptr<cmStackEntry const> parent, T value)
+    : Value(std::move(value))
+    , Parent(std::move(parent))
+  {
+  }
+
+  T mutable Value;
+  std::shared_ptr<cmStackEntry const> Parent;
+};
+
+template <typename T>
+struct cmStackEntry<T, cmStackType::Const>
+{
+  cmStackEntry(std::shared_ptr<cmStackEntry const> parent, T value)
+    : Value(std::move(value))
+    , Parent(std::move(parent))
+  {
+  }
+
+  T Value;
+  std::shared_ptr<cmStackEntry const> Parent;
+};
+
+template <typename T, typename Stack, cmStackType Mutable>
+cmStack<T, Stack, Mutable>::cmStack() = default;
+
+template <typename T, typename Stack, cmStackType Mutable>
+Stack cmStack<T, Stack, Mutable>::Push(T value) const
+{
+  return Stack(this->TopEntry, std::move(value));
+}
+
+template <typename T, typename Stack, cmStackType Mutable>
+Stack cmStack<T, Stack, Mutable>::Pop() const
+{
+  assert(this->TopEntry);
+  return Stack(this->TopEntry->Parent);
+}
+
+template <typename T, typename Stack, cmStackType Mutable>
+T const& cmStack<T, Stack, Mutable>::Top() const
+{
+  assert(this->TopEntry);
+  return this->TopEntry->Value;
+}
+
+template <typename T, typename Stack, cmStackType Mutable>
+template <bool E>
+typename std::enable_if<E, T>::type& cmStack<T, Stack, Mutable>::Top()
+{
+  static_assert(Mutable == cmStackType::Mutable,
+                "T& cmStack::Top should only exist for mutable cmStack");
+  assert(this->TopEntry);
+  return this->TopEntry->Value;
+}
+
+template <typename T, typename Stack, cmStackType Mutable>
+bool cmStack<T, Stack, Mutable>::Empty() const
+{
+  return !this->TopEntry;
+}
+
+template <typename T, typename Stack, cmStackType Mutable>
+cmStack<T, Stack, Mutable>::cmStack(std::shared_ptr<Entry const> parent,
+                                    T value)
+  : TopEntry(
+      std::make_shared<Entry const>(std::move(parent), std::move(value)))
+{
+}
+
+template <typename T, typename Stack, cmStackType Mutable>
+cmStack<T, Stack, Mutable>::cmStack(std::shared_ptr<Entry const> top)
+  : TopEntry(std::move(top))
+{
+}
diff --git a/Source/cmStandardLevel.h b/Source/cmStandardLevel.h
index dbf71b8..1f191a4 100644
--- a/Source/cmStandardLevel.h
+++ b/Source/cmStandardLevel.h
@@ -14,7 +14,7 @@
   {
   }
   size_t Index() const { return index_; }
-  friend bool operator<(cmStandardLevel const& l, cmStandardLevel const& r)
+  friend bool operator<(cmStandardLevel l, cmStandardLevel r)
   {
     return l.index_ < r.index_;
   }
diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx
index 1bb865d..d6690af 100644
--- a/Source/cmStandardLevelResolver.cxx
+++ b/Source/cmStandardLevelResolver.cxx
@@ -542,7 +542,7 @@
 }
 
 std::string cmStandardLevelResolver::GetLevelString(
-  std::string const& lang, cmStandardLevel const& level) const
+  std::string const& lang, cmStandardLevel level) const
 {
   auto mapping = StandardComputerMapping.find(lang);
   if (mapping == StandardComputerMapping.end()) {
diff --git a/Source/cmStandardLevelResolver.h b/Source/cmStandardLevelResolver.h
index 1543641..242a971 100644
--- a/Source/cmStandardLevelResolver.h
+++ b/Source/cmStandardLevelResolver.h
@@ -30,7 +30,7 @@
                                    std::string const& config) const;
 
   std::string GetLevelString(std::string const& lang,
-                             cmStandardLevel const& level) const;
+                             cmStandardLevel level) const;
 
   bool AddRequiredTargetFeature(cmTarget* target, std::string const& feature,
                                 std::string* error = nullptr) const;
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index 81f53c2..361b539 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -1030,6 +1030,7 @@
   prevPos->LinkDirectoriesPosition =
     prevPos->BuildSystemDirectory->LinkDirectories.size();
   prevPos->BuildSystemDirectory->CurrentScope = prevPos;
+  prevPos->UnwindState = pos->UnwindState;
 
   if (!pos->Keep && this->SnapshotData.IsLast(pos)) {
     if (pos->Vars != prevPos->Vars) {
diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h
index afcf1fc..2a82414 100644
--- a/Source/cmStatePrivate.h
+++ b/Source/cmStatePrivate.h
@@ -34,6 +34,8 @@
   cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator PolicyRoot;
   cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator PolicyScope;
   cmStateEnums::SnapshotType SnapshotType;
+  cmStateEnums::SnapshotUnwindType UnwindType = cmStateEnums::NO_UNWIND;
+  cmStateEnums::SnapshotUnwindState UnwindState = cmStateEnums::NOT_UNWINDING;
   bool Keep;
   cmLinkedTree<std::string>::iterator ExecutionListFile;
   cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index 3b35c4a..43d4f59 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -50,6 +50,26 @@
   return this->Position->SnapshotType;
 }
 
+cmStateEnums::SnapshotUnwindType cmStateSnapshot::GetUnwindType() const
+{
+  return this->Position->UnwindType;
+}
+
+void cmStateSnapshot::SetUnwindType(cmStateEnums::SnapshotUnwindType type)
+{
+  this->Position->UnwindType = type;
+}
+
+cmStateEnums::SnapshotUnwindState cmStateSnapshot::GetUnwindState() const
+{
+  return this->Position->UnwindState;
+}
+
+void cmStateSnapshot::SetUnwindState(cmStateEnums::SnapshotUnwindState state)
+{
+  this->Position->UnwindState = state;
+}
+
 void cmStateSnapshot::SetListFile(std::string const& listfile)
 {
   *this->Position->ExecutionListFile = listfile;
diff --git a/Source/cmStateSnapshot.h b/Source/cmStateSnapshot.h
index 07071b1..d181fad 100644
--- a/Source/cmStateSnapshot.h
+++ b/Source/cmStateSnapshot.h
@@ -44,6 +44,12 @@
   cmStateSnapshot GetCallStackBottom() const;
   cmStateEnums::SnapshotType GetType() const;
 
+  cmStateEnums::SnapshotUnwindType GetUnwindType() const;
+  void SetUnwindType(cmStateEnums::SnapshotUnwindType type);
+
+  cmStateEnums::SnapshotUnwindState GetUnwindState() const;
+  void SetUnwindState(cmStateEnums::SnapshotUnwindState state);
+
   void SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status);
   cmPolicies::PolicyStatus GetPolicy(cmPolicies::PolicyID id,
                                      bool parent_scope = false) const;
diff --git a/Source/cmStateTypes.h b/Source/cmStateTypes.h
index b3fbc13..6e2d456 100644
--- a/Source/cmStateTypes.h
+++ b/Source/cmStateTypes.h
@@ -29,6 +29,18 @@
   VariableScopeType
 };
 
+enum SnapshotUnwindType
+{
+  NO_UNWIND,
+  CAN_UNWIND
+};
+
+enum SnapshotUnwindState
+{
+  NOT_UNWINDING,
+  UNWINDING
+};
+
 // There are multiple overlapping ranges represented here. Be aware that adding
 // a value to this enumeration may cause failures in numerous places which
 // assume details about the ordering.
@@ -77,6 +89,12 @@
   RuntimeBinaryArtifact,
   ImportLibraryArtifact
 };
+
+enum class IntermediateDirKind
+{
+  ObjectFiles,
+  QtAutogenMetadata,
+};
 }
 
 namespace cmTraceEnums {
diff --git a/Source/cmString.hxx b/Source/cmString.hxx
index 3c2b49b..c346230 100644
--- a/Source/cmString.hxx
+++ b/Source/cmString.hxx
@@ -87,7 +87,7 @@
 template <>
 struct IntoString<char> : std::true_type
 {
-  static std::string into_string(char const& c) { return std::string(1, c); }
+  static std::string into_string(char c) { return std::string(1, c); }
 };
 
 /**
@@ -142,19 +142,27 @@
 template <>
 struct AsStringView<char> : std::true_type
 {
-  static string_view view(char const& s) { return string_view(&s, 1); }
+  static string_view view(
+    char const& s) // clazy:exclude=function-args-by-value
+  {
+    return string_view(&s, 1);
+  }
 };
 
 template <>
 struct AsStringView<string_view> : std::true_type
 {
-  static string_view view(string_view const& s) { return s; }
+  static string_view view(string_view s) { return s; }
 };
 
 template <>
 struct AsStringView<static_string_view> : std::true_type
 {
-  static string_view view(static_string_view const& s) { return s; }
+  static string_view view(
+    static_string_view const& s) // clazy:exclude=function-args-by-value
+  {
+    return s;
+  }
 };
 
 template <>
diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx
index a64bfc8..df3b7d9 100644
--- a/Source/cmStringAlgorithms.cxx
+++ b/Source/cmStringAlgorithms.cxx
@@ -230,7 +230,7 @@
   return cmJoinStrings(rng, separator, initial);
 }
 
-std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
+std::string cmJoin(cmStringRange rng, cm::string_view separator,
                    cm::string_view initial)
 {
   return cmJoinStrings(rng, separator, initial);
diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h
index 3bf6022..314124e 100644
--- a/Source/cmStringAlgorithms.h
+++ b/Source/cmStringAlgorithms.h
@@ -126,7 +126,7 @@
 std::string cmJoin(std::vector<std::string> const& rng,
                    cm::string_view separator, cm::string_view initial = {});
 
-std::string cmJoin(cmStringRange const& rng, cm::string_view separator,
+std::string cmJoin(cmStringRange rng, cm::string_view separator,
                    cm::string_view initial = {});
 
 enum class cmTokenizerMode
diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx
index 85c60c9..85721a3 100644
--- a/Source/cmStringCommand.cxx
+++ b/Source/cmStringCommand.cxx
@@ -1059,7 +1059,8 @@
   std::string error;
   if (!jsonReader->parse(jsonstr.data(), jsonstr.data() + jsonstr.size(),
                          &json, &error)) {
-    throw json_error(cmStrCat("failed parsing json string: "_s, error));
+    throw json_error(
+      cmStrCat("failed parsing json string:\n"_s, jsonstr, '\n', error));
   }
   return json;
 }
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index cd7fa08..f11d347 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1571,6 +1571,18 @@
         return CopyResult::Success;
       }
       break;
+    case CopyWhen::OnlyIfNewer: {
+      if (!SystemTools::FileExists(newname)) {
+        break;
+      }
+      int timeResult = 0;
+      cmsys::Status timeStatus =
+        cmsys::SystemTools::FileTimeCompare(oldname, newname, &timeResult);
+      if (timeStatus.IsSuccess() && timeResult <= 0) {
+        return CopyResult::Success;
+      }
+      break;
+    }
   }
 
   mode_t perm = 0;
@@ -1632,6 +1644,20 @@
   return CopyResult::Success;
 }
 
+bool cmSystemTools::CopyFileIfNewer(std::string const& source,
+                                    std::string const& destination)
+{
+  return cmsys::SystemTools::CopyFileIfNewer(source, destination).IsSuccess();
+}
+
+bool cmSystemTools::CopyADirectory(std::string const& source,
+                                   std::string const& destination,
+                                   CopyWhen when)
+{
+  return cmsys::SystemTools::CopyADirectory(source, destination, when)
+    .IsSuccess();
+}
+
 bool cmSystemTools::RenameFile(std::string const& oldname,
                                std::string const& newname)
 {
@@ -3296,8 +3322,8 @@
   return false;
 }
 
-static std::string::size_type cmSystemToolsFindRPath(
-  cm::string_view const& have, cm::string_view const& want)
+static std::string::size_type cmSystemToolsFindRPath(cm::string_view have,
+                                                     cm::string_view want)
 {
   std::string::size_type pos = 0;
   while (pos < have.size()) {
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 7fb2b28..5c187ec 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -167,11 +167,6 @@
   static bool SimpleGlob(std::string const& glob,
                          std::vector<std::string>& files, int type = 0);
 
-  enum class CopyWhen
-  {
-    Always,
-    OnlyIfDifferent,
-  };
   enum class CopyInputRecent
   {
     No,
@@ -210,6 +205,15 @@
                                    CopyInputRecent inputRecent,
                                    std::string* err = nullptr);
 
+  /** Copy a file if it is newer than the destination. */
+  static bool CopyFileIfNewer(std::string const& source,
+                              std::string const& destination);
+
+  /** Copy directory contents with specified copy behavior. */
+  static bool CopyADirectory(std::string const& source,
+                             std::string const& destination,
+                             CopyWhen when = CopyWhen::Always);
+
   enum class Replace
   {
     Yes,
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 8c4973a..cbf8b90 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -589,6 +589,7 @@
 {
 public:
   cmStateEnums::TargetType TargetType;
+  cmTarget::Origin Origin = cmTarget::Origin::Unknown;
   cmMakefile* Makefile;
   cmPolicies::PolicyMap PolicyMap;
   cmTarget const* TemplateTarget;
@@ -1112,6 +1113,18 @@
   return this->impl->TargetType;
 }
 
+void cmTarget::SetOrigin(Origin origin)
+{
+  assert(origin != cmTarget::Origin::Unknown);
+  assert(this->impl->Origin == cmTarget::Origin::Unknown);
+  this->impl->Origin = origin;
+}
+
+cmTarget::Origin cmTarget::GetOrigin() const
+{
+  return this->impl->Origin;
+}
+
 cmMakefile* cmTarget::GetMakefile() const
 {
   return this->impl->Makefile;
@@ -1613,7 +1626,7 @@
 }
 
 void cmTarget::AddInstallIncludeDirectories(cmTargetExport const& te,
-                                            cmStringRange const& incs)
+                                            cmStringRange incs)
 {
   std::copy(
     incs.begin(), incs.end(),
@@ -1911,7 +1924,6 @@
 MAKE_PROP(COMPILE_FEATURES);
 MAKE_PROP(COMPILE_OPTIONS);
 MAKE_PROP(PRECOMPILE_HEADERS);
-MAKE_PROP(PRECOMPILE_HEADERS_REUSE_FROM);
 MAKE_PROP(CUDA_CUBIN_COMPILATION);
 MAKE_PROP(CUDA_FATBIN_COMPILATION);
 MAKE_PROP(CUDA_OPTIX_COMPILATION);
@@ -2147,38 +2159,6 @@
       this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
       return;
     }
-  } else if (prop == propPRECOMPILE_HEADERS_REUSE_FROM) {
-    if (this->GetProperty("PRECOMPILE_HEADERS")) {
-      std::ostringstream e;
-      e << "PRECOMPILE_HEADERS property is already set on target (\""
-        << this->impl->Name << "\")\n";
-      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
-      return;
-    }
-    auto* reusedTarget = this->impl->Makefile->GetCMakeInstance()
-                           ->GetGlobalGenerator()
-                           ->FindTarget(value);
-    if (!reusedTarget) {
-      std::string const e(
-        "PRECOMPILE_HEADERS_REUSE_FROM set with non existing target");
-      this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e);
-      return;
-    }
-
-    std::string reusedFrom = reusedTarget->GetSafeProperty(prop);
-    if (reusedFrom.empty()) {
-      reusedFrom = *value;
-    }
-
-    this->impl->Properties.SetProperty(prop, reusedFrom);
-
-    reusedTarget->SetProperty("COMPILE_PDB_NAME", reusedFrom);
-    reusedTarget->SetProperty("COMPILE_PDB_OUTPUT_DIRECTORY",
-                              cmStrCat(reusedFrom, ".dir/"));
-
-    cmValue tmp = reusedTarget->GetProperty("COMPILE_PDB_NAME");
-    this->SetProperty("COMPILE_PDB_NAME", tmp);
-    this->AddUtility(reusedFrom, false, this->impl->Makefile);
   } else if (prop == propC_STANDARD || prop == propCXX_STANDARD ||
              prop == propCUDA_STANDARD || prop == propHIP_STANDARD ||
              prop == propOBJC_STANDARD || prop == propOBJCXX_STANDARD) {
@@ -2208,15 +2188,6 @@
                "imported targets (\"",
                this->impl->Name, "\")\n"));
   }
-  if (prop == propPRECOMPILE_HEADERS &&
-      this->GetProperty("PRECOMPILE_HEADERS_REUSE_FROM")) {
-    this->impl->Makefile->IssueMessage(
-      MessageType::FATAL_ERROR,
-      cmStrCat(
-        "PRECOMPILE_HEADERS_REUSE_FROM property is already set on target (\"",
-        this->impl->Name, "\")\n"));
-    return;
-  }
 
   UsageRequirementProperty* usageRequirements[] = {
     &this->impl->IncludeDirectories,
@@ -2432,8 +2403,7 @@
 }
 }
 
-void cmTarget::FinalizeTargetConfiguration(
-  cmBTStringRange const& compileDefinitions)
+void cmTarget::FinalizeTargetConfiguration(cmBTStringRange compileDefinitions)
 {
   if (this->GetType() == cmStateEnums::GLOBAL_TARGET) {
     return;
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 2bddec5..1c2a9b2 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -51,6 +51,12 @@
     Foreign,
   };
 
+  enum class Origin
+  {
+    Cps,
+    Unknown,
+  };
+
   enum class PerConfig
   {
     Yes,
@@ -70,6 +76,12 @@
   //! Return the type of target.
   cmStateEnums::TargetType GetType() const;
 
+  //! Set the origin of the target.
+  void SetOrigin(Origin origin);
+
+  //! Return the origin of the target.
+  Origin GetOrigin() const;
+
   //! Get the cmMakefile that owns this target.
   cmMakefile* GetMakefile() const;
 
@@ -260,7 +272,7 @@
   void InsertPrecompileHeader(BT<std::string> const& entry);
 
   void AppendBuildInterfaceIncludes();
-  void FinalizeTargetConfiguration(cmBTStringRange const& compileDefinitions);
+  void FinalizeTargetConfiguration(cmBTStringRange compileDefinitions);
 
   std::string GetDebugGeneratorExpressions(std::string const& value,
                                            cmTargetLinkLibraryType llt) const;
@@ -269,7 +281,7 @@
   std::set<std::string> const& GetSystemIncludeDirectories() const;
 
   void AddInstallIncludeDirectories(cmTargetExport const& te,
-                                    cmStringRange const& incs);
+                                    cmStringRange incs);
   cmStringRange GetInstallIncludeDirectoriesEntries(
     cmTargetExport const& te) const;
 
diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx
index 9f42769..40d3d8a 100644
--- a/Source/cmTryCompileCommand.cxx
+++ b/Source/cmTryCompileCommand.cxx
@@ -22,7 +22,7 @@
                           cmTryCompileResult const& compileResult)
 {
   // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
-  static std::vector<unsigned long> const LogVersionsWithTryCompileV1{ 1 };
+  static std::vector<unsigned int> const LogVersionsWithTryCompileV1{ 1 };
 
   if (log.IsAnyLogVersionEnabled(LogVersionsWithTryCompileV1)) {
     log.BeginEvent("try_compile-v1", mf);
diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx
index f6436c6..0889ff0 100644
--- a/Source/cmTryRunCommand.cxx
+++ b/Source/cmTryRunCommand.cxx
@@ -41,7 +41,7 @@
                       cmTryRunResult const& runResult)
 {
   // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames.
-  static std::vector<unsigned long> const LogVersionsWithTryRunV1{ 1 };
+  static std::vector<unsigned int> const LogVersionsWithTryRunV1{ 1 };
 
   if (log.IsAnyLogVersionEnabled(LogVersionsWithTryRunV1)) {
     log.BeginEvent("try_run-v1", mf);
diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx
index 4910653..e551083 100644
--- a/Source/cmUVProcessChain.cxx
+++ b/Source/cmUVProcessChain.cxx
@@ -564,7 +564,7 @@
       case STATUS_NO_MEMORY:
       default: {
         char buf[256];
-        snprintf(buf, sizeof(buf), "Exit code 0x%x\n",
+        snprintf(buf, sizeof(buf), "Exit code 0x%x",
                  static_cast<unsigned int>(this->ExitStatus));
         return std::make_pair(ExceptionCode::Other, buf);
       }
diff --git a/Source/cmUnsetCommand.cxx b/Source/cmUnsetCommand.cxx
index d34627c..117118c 100644
--- a/Source/cmUnsetCommand.cxx
+++ b/Source/cmUnsetCommand.cxx
@@ -28,6 +28,14 @@
 #endif
     return true;
   }
+  // unset(CACHE{VAR})
+  if (cmHasLiteralPrefix(variable, "CACHE{") && variable.size() > 7 &&
+      cmHasLiteralSuffix(variable, "}")) {
+    // get the variable name
+    auto const& varName = variable.substr(6, variable.size() - 7);
+    status.GetMakefile().RemoveCacheDefinition(varName);
+    return true;
+  }
   // unset(VAR)
   if (args.size() == 1) {
     status.GetMakefile().RemoveDefinition(variable);
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 13d4b42..d53987b 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -2721,6 +2721,18 @@
         this->WriteExcludeFromBuild(e2, exclude_configs);
       }
 
+      if (this->GlobalGenerator->UseShortObjectNames()) {
+        std::string outputName = "ObjectFileName";
+        if (si.Source->GetLanguage() == "CUDA"_s) {
+          outputName = "CompileOut";
+        }
+        e2.Element(
+          outputName,
+          cmStrCat("$(IntDir)",
+                   this->LocalGenerator->GetShortObjectFileName(*si.Source),
+                   ".obj"));
+      }
+
       this->FinishWritingSource(e2, toolSettings);
     } else if (fs && fs->GetType() == "CXX_MODULES"_s) {
       this->GeneratorTarget->Makefile->IssueMessage(
@@ -3078,9 +3090,20 @@
   for (std::string const& config : this->Configurations) {
     std::string const cond = this->CalcCondition(config);
 
+    std::string fullIntermediateDir =
+      cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/');
+    cmSystemTools::MakeDirectory(fullIntermediateDir);
+    std::string intermediateDir =
+      this->LocalGenerator->MaybeRelativeToCurBinDir(fullIntermediateDir);
+    ConvertToWindowsSlash(intermediateDir);
+
     if (ttype >= cmStateEnums::UTILITY) {
-      e1.WritePlatformConfigTag(
-        "IntDir", cond, R"($(Platform)\$(Configuration)\$(ProjectName)\)");
+      if (this->GlobalGenerator->UseShortObjectNames()) {
+        e1.WritePlatformConfigTag("IntDir", cond, intermediateDir);
+      } else {
+        e1.WritePlatformConfigTag(
+          "IntDir", cond, R"($(Platform)\$(Configuration)\$(ProjectName)\)");
+      }
     } else {
       if (ttype == cmStateEnums::SHARED_LIBRARY ||
           ttype == cmStateEnums::MODULE_LIBRARY ||
@@ -3092,9 +3115,6 @@
         }
       }
 
-      std::string intermediateDir =
-        this->LocalGenerator->MaybeRelativeToCurBinDir(cmStrCat(
-          this->GeneratorTarget->GetSupportDirectory(), '/', config, '/'));
       std::string outDir;
       std::string targetNameFull;
       if (ttype == cmStateEnums::OBJECT_LIBRARY) {
@@ -3104,7 +3124,6 @@
         outDir = cmStrCat(this->GeneratorTarget->GetDirectory(config), '/');
         targetNameFull = this->GeneratorTarget->GetFullName(config);
       }
-      ConvertToWindowsSlash(intermediateDir);
       ConvertToWindowsSlash(outDir);
 
       e1.WritePlatformConfigTag("OutDir", cond, outDir);
@@ -5614,7 +5633,8 @@
   this->AddedFiles.push_back(smallLogo);
 
   std::string logo = cmStrCat(this->DefaultArtifactDir, "/Logo.png");
-  cmSystemTools::CopyAFile(cmStrCat(templateFolder, "/Logo.png"), logo, false);
+  cmSystemTools::CopyAFile(cmStrCat(templateFolder, "/Logo.png"), logo,
+                           cmSystemTools::CopyWhen::OnlyIfDifferent);
   ConvertToWindowsSlash(logo);
   Elem(e1, "Image").Attribute("Include", logo);
   this->AddedFiles.push_back(logo);
@@ -5894,7 +5914,8 @@
   this->AddedFiles.push_back(smallLogo44);
 
   std::string logo = cmStrCat(this->DefaultArtifactDir, "/Logo.png");
-  cmSystemTools::CopyAFile(cmStrCat(templateFolder, "/Logo.png"), logo, false);
+  cmSystemTools::CopyAFile(cmStrCat(templateFolder, "/Logo.png"), logo,
+                           cmSystemTools::CopyWhen::OnlyIfDifferent);
   ConvertToWindowsSlash(logo);
   Elem(e1, "Image").Attribute("Include", logo);
   this->AddedFiles.push_back(logo);
diff --git a/Source/cmWindowsRegistry.cxx b/Source/cmWindowsRegistry.cxx
index 0a0add3..154e6d9 100644
--- a/Source/cmWindowsRegistry.cxx
+++ b/Source/cmWindowsRegistry.cxx
@@ -524,7 +524,7 @@
 template <>
 struct hash<cmWindowsRegistry::View>
 {
-  size_t operator()(cmWindowsRegistry::View const& v) const noexcept
+  size_t operator()(cmWindowsRegistry::View v) const noexcept
   {
     return static_cast<
       typename underlying_type<cmWindowsRegistry::View>::type>(v);
diff --git a/Source/cmXMLWriter.h b/Source/cmXMLWriter.h
index ba4f763..e15542d 100644
--- a/Source/cmXMLWriter.h
+++ b/Source/cmXMLWriter.h
@@ -108,8 +108,7 @@
    * Therefore we must assume it is an arbitrary point in time. Instead of this
    * method, it is recommended to convert it by means of the to_time_t method.
    */
-  static std::time_t SafeContent(
-    std::chrono::system_clock::time_point const& value)
+  static std::time_t SafeContent(std::chrono::system_clock::time_point value)
   {
     return std::chrono::system_clock::to_time_t(value);
   }
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 0651405..7cc0738 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -455,8 +455,8 @@
 
 #ifndef CMAKE_BOOTSTRAP
 void cmake::SetWarningFromPreset(std::string const& name,
-                                 cm::optional<bool> const& warning,
-                                 cm::optional<bool> const& error)
+                                 cm::optional<bool> warning,
+                                 cm::optional<bool> error)
 {
   if (warning) {
     if (*warning) {
@@ -933,6 +933,10 @@
   readGeneratorVar("CMAKE_GENERATOR_INSTANCE", this->GeneratorInstance);
   readGeneratorVar("CMAKE_GENERATOR_PLATFORM", this->GeneratorPlatform);
   readGeneratorVar("CMAKE_GENERATOR_TOOLSET", this->GeneratorToolset);
+  this->IntermediateDirStrategy =
+    cmSystemTools::GetEnvVar("CMAKE_INTERMEDIATE_DIR_STRATEGY");
+  this->AutogenIntermediateDirStrategy =
+    cmSystemTools::GetEnvVar("CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY");
 }
 
 namespace {
@@ -2600,6 +2604,23 @@
                         "Name of generator toolset.", cmStateEnums::INTERNAL);
   }
 
+  if (!this->State->GetInitializedCacheValue(
+        "CMAKE_INTERMEDIATE_DIR_STRATEGY") &&
+      this->IntermediateDirStrategy) {
+    this->AddCacheEntry(
+      "CMAKE_INTERMEDIATE_DIR_STRATEGY", *this->IntermediateDirStrategy,
+      "Select the intermediate directory strategy", cmStateEnums::INTERNAL);
+  }
+  if (!this->State->GetInitializedCacheValue(
+        "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY") &&
+      this->AutogenIntermediateDirStrategy) {
+    this->AddCacheEntry(
+      "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY",
+      *this->AutogenIntermediateDirStrategy,
+      "Select the intermediate directory strategy for Autogen",
+      cmStateEnums::INTERNAL);
+  }
+
   if (!this->State->GetInitializedCacheValue("CMAKE_TEST_LAUNCHER")) {
     cm::optional<std::string> testLauncher =
       cmSystemTools::GetEnvVar("CMAKE_TEST_LAUNCHER");
@@ -2643,7 +2664,7 @@
     this->ConfigureLog = cm::make_unique<cmConfigureLog>(
       cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles"_s),
       this->FileAPI->GetConfigureLogVersions());
-    this->Instrumentation->LoadQueries();
+    this->Instrumentation->CheckCDashVariable();
   }
 #endif
 
@@ -2709,7 +2730,8 @@
     if (mf->IsOn("CTEST_USE_LAUNCHERS")) {
       launcher = cmStrCat('"', cmSystemTools::GetCTestCommand(),
                           "\" --launch "
-                          "--current-build-dir <CMAKE_CURRENT_BINARY_DIR> ");
+                          "--current-build-dir <CMAKE_CURRENT_BINARY_DIR> "
+                          "--object-dir <TARGET_SUPPORT_DIR> ");
     } else {
       launcher =
         cmStrCat('"', cmSystemTools::GetCTestCommand(), "\" --instrument ");
@@ -3086,10 +3108,6 @@
         << ms.count() / 1000.0L << "s)";
     this->UpdateProgress(msg.str(), -1);
   }
-#if !defined(CMAKE_BOOTSTRAP)
-  this->Instrumentation->CollectTimingData(
-    cmInstrumentationQuery::Hook::PostGenerate);
-#endif
   if (!this->GraphVizFile.empty()) {
     std::cout << "Generate graphviz: " << this->GraphVizFile << '\n';
     this->GenerateGraphViz(this->GraphVizFile);
@@ -3109,6 +3127,8 @@
   this->SaveCache(this->GetHomeOutputDirectory());
 
 #if !defined(CMAKE_BOOTSTRAP)
+  this->Instrumentation->CollectTimingData(
+    cmInstrumentationQuery::Hook::PostGenerate);
   this->GlobalGenerator->WriteInstallJson();
   this->FileAPI->WriteReplies(cmFileAPI::IndexFor::Success);
 #endif
@@ -4021,6 +4041,9 @@
   };
 
 #if !defined(CMAKE_BOOTSTRAP)
+  // Block the instrumentation build daemon from spawning during this build.
+  // This lock will be released when the process exits at the end of the build.
+  instrumentation.LockBuildDaemon();
   int buildresult =
     instrumentation.InstrumentCommand("cmakeBuild", args, doBuild);
   instrumentation.CollectTimingData(
diff --git a/Source/cmake.h b/Source/cmake.h
index f338c13..c859beb 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -388,8 +388,8 @@
 
 #ifndef CMAKE_BOOTSTRAP
   void SetWarningFromPreset(std::string const& name,
-                            cm::optional<bool> const& warning,
-                            cm::optional<bool> const& error);
+                            cm::optional<bool> warning,
+                            cm::optional<bool> error);
   void ProcessPresetVariables();
   void PrintPresetVariables();
   void ProcessPresetEnvironment();
@@ -768,6 +768,8 @@
   std::string GeneratorInstance;
   std::string GeneratorPlatform;
   std::string GeneratorToolset;
+  cm::optional<std::string> IntermediateDirStrategy;
+  cm::optional<std::string> AutogenIntermediateDirStrategy;
   bool GeneratorInstanceSet = false;
   bool GeneratorPlatformSet = false;
   bool GeneratorToolsetSet = false;
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 66efbd3..805bdab 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -97,7 +97,9 @@
   copy <file>... destination  - copy files to destination (either file or directory)
   copy_directory <dir>... destination   - copy content of <dir>... directories to 'destination' directory
   copy_directory_if_different <dir>... destination   - copy changed content of <dir>... directories to 'destination' directory
+  copy_directory_if_newer <dir>... destination   - copy newer content of <dir>... directories to 'destination' directory
   copy_if_different <file>... destination  - copy files if it has changed
+  copy_if_newer <file>... destination  - copy files if source is newer than destination
   echo [<string>...]        - displays arguments as text
   echo_append [<string>...] - displays arguments as text but no new line
   env [--unset=NAME ...] [NAME=VALUE ...] [--] <command> [<arg>...]
@@ -778,15 +780,45 @@
       return return_value;
     }
 
+    // Copy file if newer.
+    if (args[1] == "copy_if_newer" && args.size() > 3) {
+      // If multiple source files specified,
+      // then destination must be directory
+      if ((args.size() > 4) &&
+          (!cmSystemTools::FileIsDirectory(args.back()))) {
+        std::cerr << "Error: Target (for copy_if_newer command) \""
+                  << args.back() << "\" is not a directory.\n";
+        return 1;
+      }
+      // If error occurs we want to continue copying next files.
+      bool return_value = false;
+      for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
+        if (!cmSystemTools::CopyFileIfNewer(arg, args.back())) {
+          std::cerr << "Error copying file (if newer) from \"" << arg
+                    << "\" to \"" << args.back() << "\".\n";
+          return_value = true;
+        }
+      }
+      return return_value;
+    }
+
     // Copy directory contents
     if ((args[1] == "copy_directory" ||
-         args[1] == "copy_directory_if_different") &&
+         args[1] == "copy_directory_if_different" ||
+         args[1] == "copy_directory_if_newer") &&
         args.size() > 3) {
       // If error occurs we want to continue copying next files.
       bool return_value = false;
-      bool const copy_always = (args[1] == "copy_directory");
+
+      cmsys::SystemTools::CopyWhen when = cmsys::SystemTools::CopyWhen::Always;
+      if (args[1] == "copy_directory_if_different") {
+        when = cmsys::SystemTools::CopyWhen::OnlyIfDifferent;
+      } else if (args[1] == "copy_directory_if_newer") {
+        when = cmsys::SystemTools::CopyWhen::OnlyIfNewer;
+      }
+
       for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) {
-        if (!cmSystemTools::CopyADirectory(arg, args.back(), copy_always)) {
+        if (!cmSystemTools::CopyADirectory(arg, args.back(), when)) {
           std::cerr << "Error copying directory from \"" << arg << "\" to \""
                     << args.back() << "\".\n";
           return_value = true;
@@ -1361,6 +1393,7 @@
       std::string homeOutDir;
       std::string startOutDir;
       std::string depInfo;
+      std::string targetName;
       bool color = false;
       if (args.size() >= 8) {
         // Full signature:
@@ -1369,6 +1402,7 @@
         //                    <home-src-dir> <start-src-dir>
         //                    <home-out-dir> <start-out-dir>
         //                    <dep-info> [--color=$(COLOR)]
+        //                    <target-name>
         //
         // All paths are provided.
         gen = args[2];
@@ -1377,10 +1411,19 @@
         homeOutDir = args[5];
         startOutDir = args[6];
         depInfo = args[7];
+        size_t targetNameIdx = 8;
         if (args.size() >= 9 && cmHasLiteralPrefix(args[8], "--color=")) {
           // Enable or disable color based on the switch value.
+          targetNameIdx = 9;
           color = (args[8].size() == 8 || cmIsOn(args[8].substr(8)));
         }
+        if (args.size() > targetNameIdx) {
+          targetName = args[targetNameIdx];
+        } else {
+          std::string targetDir = cmSystemTools::GetFilenamePath(depInfo);
+          targetDir = cmSystemTools::GetFilenameName(targetDir);
+          targetName = targetDir.substr(0, targetDir.size() - 4);
+        }
       } else {
         // Support older signature for existing makefiles:
         //
@@ -1396,6 +1439,10 @@
         homeOutDir = args[3];
         startOutDir = args[3];
         depInfo = args[5];
+        // Strip the `.dir` suffix. Old CMake always uses this pattern.
+        std::string targetDir = cmSystemTools::GetFilenamePath(depInfo);
+        targetDir = cmSystemTools::GetFilenameName(targetDir);
+        targetName = targetDir.substr(0, targetDir.size() - 4);
       }
 
       // Create a local generator configured for the directory in
@@ -1421,7 +1468,9 @@
         lgd->SetRelativePathTop(homeDir, homeOutDir);
 
         // Actually scan dependencies.
-        return lgd->UpdateDependencies(depInfo, verbose, color) ? 0 : 2;
+        return lgd->UpdateDependencies(depInfo, targetName, verbose, color)
+          ? 0
+          : 2;
       }
       return 1;
     }
@@ -2246,7 +2295,9 @@
   std::vector<std::string> expandedArgs;
   for (std::string const& i : args) {
     // check for nmake temporary files
-    if (i[0] == '@' && !cmHasLiteralPrefix(i, "@CMakeFiles")) {
+    if (i[0] == '@' &&
+        !(cmHasLiteralPrefix(i, "@CMakeFiles") ||
+          cmHasLiteralPrefix(i, "@.o/") || cmHasLiteralPrefix(i, "@.o\\"))) {
       cmsys::ifstream fin(i.substr(1).c_str());
       std::string line;
       while (cmSystemTools::GetLineFromStream(fin, line)) {
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index 75f9bb8..69f7ac0 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -911,12 +911,6 @@
 # Setup testing if not being built as part of another project.
 if(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
   if(BUILD_TESTING)
-    # Compute the location of executables.
-    set(EXEC_DIR "${CMAKE_CURRENT_BINARY_DIR}")
-    if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
-      set(EXEC_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
-    endif()
-
     # C tests
     set(KWSYS_C_TESTS
       testEncode.c
@@ -934,7 +928,7 @@
     foreach(testfile IN LISTS KWSYS_C_TESTS)
       get_filename_component(test "${testfile}" NAME_WE)
       add_test(NAME kwsys.${test}
-        COMMAND ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}}
+        COMMAND ${KWSYS_NAMESPACE}TestsC ${test} ${KWSYS_TEST_ARGS_${test}}
         )
       set_property(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
     endforeach()
@@ -982,7 +976,10 @@
       KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
       ${KWSYS_CXX_TESTS}
       )
-    add_executable(${KWSYS_NAMESPACE}TestsCxx ${KWSYS_CXX_TEST_SRCS})
+    add_executable(${KWSYS_NAMESPACE}TestsCxx
+      ${KWSYS_CXX_TEST_SRCS}
+      test.manifest
+    )
     set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_CLANG_TIDY "")
     set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY CXX_CLANG_TIDY "")
     set_property(TARGET ${KWSYS_NAMESPACE}TestsCxx PROPERTY C_INCLUDE_WHAT_YOU_USE "")
@@ -1038,7 +1035,7 @@
     foreach(testfile IN LISTS KWSYS_CXX_TESTS)
       get_filename_component(test "${testfile}" NAME_WE)
       add_test(NAME kwsys.${test}
-        COMMAND ${EXEC_DIR}/${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}}
+        COMMAND ${KWSYS_NAMESPACE}TestsCxx ${test} ${KWSYS_TEST_ARGS_${test}}
         )
       set_property(TEST kwsys.${test} PROPERTY LABELS ${KWSYS_LABELS_TEST})
     endforeach()
@@ -1050,7 +1047,7 @@
     #set(KWSYS_TEST_PROCESS_7 7) # uncomment to run timing-sensitive test locally
     foreach(n IN ITEMS 1 2 3 4 5 6 ${KWSYS_TEST_PROCESS_7} 9 10)
       add_test(NAME kwsys.testProcess-${n}
-        COMMAND ${EXEC_DIR}/${KWSYS_NAMESPACE}TestProcess ${n}
+        COMMAND ${KWSYS_NAMESPACE}TestProcess ${n}
         )
       set_property(TEST kwsys.testProcess-${n} PROPERTY LABELS ${KWSYS_LABELS_TEST})
       set_property(TEST kwsys.testProcess-${n} PROPERTY TIMEOUT 120)
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 39357f6..26ec57d 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -2145,7 +2145,7 @@
     default:
       cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other;
       snprintf(cp->ProcessResults[idx].ExitExceptionString,
-               KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code);
+               KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x", code);
       break;
   }
 }
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index c65587e..a11487d 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -44,6 +44,7 @@
 #include <fstream>
 #include <iostream>
 #include <limits>
+#include <map>
 #include <set>
 #include <sstream>
 #include <string>
@@ -5324,14 +5325,7 @@
 
   this->OSName = "Windows";
 
-  OSVERSIONINFOEXW osvi;
-  BOOL bIsWindows64Bit;
-  BOOL bOsVersionInfoEx;
-  char operatingSystem[256];
-
-  // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
-  ZeroMemory(&osvi, sizeof(OSVERSIONINFOEXW));
-  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
+  OSVERSIONINFOEXW osvi = { sizeof(osvi) };
 #  ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
 #    pragma warning(push)
 #    ifdef __INTEL_COMPILER
@@ -5343,12 +5337,8 @@
 #      pragma warning(disable : 4996)
 #    endif
 #  endif
-  bOsVersionInfoEx = GetVersionExW((OSVERSIONINFOW*)&osvi);
-  if (!bOsVersionInfoEx) {
-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
-    if (!GetVersionExW((OSVERSIONINFOW*)&osvi)) {
-      return false;
-    }
+  if (!GetVersionExW((OSVERSIONINFOW*)&osvi)) {
+    return false;
   }
 #  ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
 #    ifdef __clang__
@@ -5358,167 +5348,91 @@
 #    endif
 #  endif
 
-  switch (osvi.dwPlatformId) {
-    case VER_PLATFORM_WIN32_NT:
-      // Test for the product.
-      if (osvi.dwMajorVersion <= 4) {
-        this->OSRelease = "NT";
-      }
-      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
-        this->OSRelease = "2000";
-      }
-      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
-        this->OSRelease = "XP";
-      }
-      // XP Professional x64
-      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
-        this->OSRelease = "XP";
-      }
-#  ifdef VER_NT_WORKSTATION
-      // Test for product type.
-      if (bOsVersionInfoEx) {
-        if (osvi.wProductType == VER_NT_WORKSTATION) {
-          if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
-            this->OSRelease = "Vista";
-          }
-          if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1) {
-            this->OSRelease = "7";
-          }
-// VER_SUITE_PERSONAL may not be defined
-#    ifdef VER_SUITE_PERSONAL
-          else {
-            if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
-              this->OSRelease += " Personal";
-            } else {
-              this->OSRelease += " Professional";
-            }
-          }
-#    endif
-        } else if (osvi.wProductType == VER_NT_SERVER) {
-          // Check for .NET Server instead of Windows XP.
-          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
-            this->OSRelease = ".NET";
-          }
+  // Produce the release like it is displayed in `cmd`
+  this->OSRelease = std::to_string(osvi.dwMajorVersion) + "." +
+    std::to_string(osvi.dwMinorVersion) + "." +
+    std::to_string(osvi.dwBuildNumber & 0xFFFF);
 
-          // Continue with the type detection.
-          if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
-            this->OSRelease += " DataCenter Server";
-          } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
-            this->OSRelease += " Advanced Server";
-          } else {
-            this->OSRelease += " Server";
-          }
-        }
+  struct VersionNames
+  {
+    char const* workstation;
+    char const* server;
+  };
 
-        snprintf(operatingSystem, sizeof(operatingSystem), "%ls (Build %ld)",
-                 osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
-        this->OSVersion = operatingSystem;
-      } else
-#  endif // VER_NT_WORKSTATION
-      {
-        HKEY hKey;
-        wchar_t szProductType[80];
-        DWORD dwBufLen;
+  std::map<std::pair<DWORD, DWORD>, VersionNames> const products = {
+    // clang-format off
+    { { 10,  0 }, { "10",    "2016"    } },
+    { {  6,  3 }, { "8.1",   "2012 R2" } },
+    { {  6,  2 }, { "8",     "2012"    } },
+    { {  6,  1 }, { "7",     "2008 R2" } },
+    { {  6,  0 }, { "Vista", "2008"    } },
+    { {  5,  2 }, { "XP",    "2003"    } },
+    { {  5,  1 }, { "XP",    ".NET"    } },
+    { {  5,  0 }, { "2000",  "2000"    } },
+    { {  4, 90 }, { "Me",    ""        } },
+    { {  4, 10 }, { "98",    ""        } },
+    { {  4,  0 }, { "95",    "NT 4.0"  } },
+    { {  3, 51 }, {   "",    "NT 3.51" } },
+    { {  3, 10 }, { "3.1",   ""        } },
+    { {  3,  0 }, { "3.0",   ""        } },
+    { {  2,  0 }, { "2.0",   ""        } },
+    // clang-format on
+  };
 
-        // Query the registry to retrieve information.
-        RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-                      L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0,
-                      KEY_QUERY_VALUE, &hKey);
-        RegQueryValueExW(hKey, L"ProductType", nullptr, nullptr,
-                         (LPBYTE)szProductType, &dwBufLen);
-        RegCloseKey(hKey);
+  this->OSVersion = "Windows ";
+  if (osvi.wProductType == VER_NT_SERVER) {
+    this->OSVersion += "Server ";
+  }
 
-        if (lstrcmpiW(L"WINNT", szProductType) == 0) {
-          this->OSRelease += " Professional";
-        }
-        if (lstrcmpiW(L"LANMANNT", szProductType) == 0) {
-          // Decide between Windows 2000 Advanced Server and Windows .NET
-          // Enterprise Server.
-          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
-            this->OSRelease += " Standard Server";
-          } else {
-            this->OSRelease += " Server";
-          }
-        }
-        if (lstrcmpiW(L"SERVERNT", szProductType) == 0) {
-          // Decide between Windows 2000 Advanced Server and Windows .NET
-          // Enterprise Server.
-          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
-            this->OSRelease += " Enterprise Server";
-          } else {
-            this->OSRelease += " Advanced Server";
-          }
-        }
-      }
+  auto const it = products.find({ osvi.dwMajorVersion, osvi.dwMinorVersion });
+  if (it != products.end()) {
+    bool const useServer =
+      (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+       (osvi.dwMajorVersion <= 4 || osvi.wProductType != VER_NT_WORKSTATION));
+    this->OSVersion += useServer ? it->second.server : it->second.workstation;
+  } else {
+    this->OSVersion += "Unknown Version";
+  }
 
-      // Display version, service pack (if any), and build number.
-      if (osvi.dwMajorVersion <= 4) {
-        // NB: NT 4.0 and earlier.
-        snprintf(operatingSystem, sizeof(operatingSystem),
-                 "version %ld.%ld %ls (Build %ld)", osvi.dwMajorVersion,
-                 osvi.dwMinorVersion, osvi.szCSDVersion,
-                 osvi.dwBuildNumber & 0xFFFF);
-        this->OSVersion = operatingSystem;
-      } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
-        // Windows XP and .NET server.
-        using LPFNPROC = BOOL(CALLBACK*)(HANDLE, BOOL*);
-        HINSTANCE hKernelDLL;
-        LPFNPROC DLLProc;
+  if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
+    // special case for Windows XP x64
+    if (osvi.wProductType == VER_NT_WORKSTATION) {
+      this->OSVersion += " x64";
+    }
 
-        // Load the Kernel32 DLL.
-        hKernelDLL = LoadLibraryW(L"kernel32");
-        if (hKernelDLL != nullptr) {
-          // Only XP and .NET Server support IsWOW64Process so... Load
-          // dynamically!
-          DLLProc = (LPFNPROC)GetProcAddress(hKernelDLL, "IsWow64Process");
+    // special case for Windows Server 2003 R2
+    else if (GetSystemMetrics(SM_SERVERR2) != 0) {
+      this->OSVersion += " R2";
+    }
+  }
 
-          // If the function address is valid, call the function.
-          if (DLLProc != nullptr)
-            (DLLProc)(GetCurrentProcess(), &bIsWindows64Bit);
-          else
-            bIsWindows64Bit = false;
+  // special case for Windows 98 SE
+  else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
+    if (osvi.szCSDVersion[1] == 'A') {
+      this->OSVersion += " SE";
+    }
+  }
 
-          // Free the DLL module.
-          FreeLibrary(hKernelDLL);
-        }
-      } else {
-        // Windows 2000 and everything else.
-        snprintf(operatingSystem, sizeof(operatingSystem), "%ls (Build %ld)",
-                 osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
-        this->OSVersion = operatingSystem;
-      }
-      break;
+  // special case for Windows 95 OSR 2
+  else if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
+    if (osvi.szCSDVersion[1] == 'C') {
+      this->OSVersion += " OSR 2.5";
+    } else if (osvi.szCSDVersion[1] == 'B') {
+      this->OSVersion += " OSR 2";
+    }
+  }
 
-    case VER_PLATFORM_WIN32_WINDOWS:
-      // Test for the product.
-      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
-        this->OSRelease = "95";
-        if (osvi.szCSDVersion[1] == 'C') {
-          this->OSRelease += "OSR 2.5";
-        } else if (osvi.szCSDVersion[1] == 'B') {
-          this->OSRelease += "OSR 2";
-        }
-      }
+  if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+    this->OSVersion += " DataCenter";
+  } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+    this->OSVersion += " Enterprise";
+  }
 
-      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
-        this->OSRelease = "98";
-        if (osvi.szCSDVersion[1] == 'A') {
-          this->OSRelease += "SE";
-        }
-      }
-
-      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
-        this->OSRelease = "Me";
-      }
-      break;
-
-    case VER_PLATFORM_WIN32s:
-      this->OSRelease = "Win32s";
-      break;
-
-    default:
-      this->OSRelease = "Unknown";
-      break;
+  // append service pack (if any)
+  if (osvi.szCSDVersion[0] != 0 && osvi.szCSDVersion[0] != ' ') {
+    char buffer[256];
+    snprintf(buffer, sizeof(buffer), " %ls", osvi.szCSDVersion);
+    this->OSVersion += buffer;
   }
 
   // Get the hostname
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 595bec0..3a2dc5a 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -2247,6 +2247,48 @@
   return CopyStatus{ Status::Success(), CopyStatus::NoPath };
 }
 
+SystemTools::CopyStatus SystemTools::CopyFileIfNewer(
+  std::string const& source, std::string const& destination)
+{
+  // special check for a destination that is a directory
+  // FileTimeCompare does not handle file to directory compare
+  if (SystemTools::FileIsDirectory(destination)) {
+    std::string const new_destination = FileInDir(source, destination);
+    if (!SystemTools::ComparePath(new_destination, destination)) {
+      return SystemTools::CopyFileIfNewer(source, new_destination);
+    }
+    // If source and destination are the same path, don't copy
+    return CopyStatus{ Status::Success(), CopyStatus::NoPath };
+  }
+
+  // source and destination are files so do a copy if source is newer
+  // Check if source file exists first
+  if (!SystemTools::FileExists(source)) {
+    return CopyStatus{ Status::POSIX_errno(), CopyStatus::SourcePath };
+  }
+  // If destination doesn't exist, always copy
+  if (!SystemTools::FileExists(destination)) {
+    return SystemTools::CopyFileAlways(source, destination);
+  }
+  // Check if source is newer than destination
+  int timeResult;
+  Status timeStatus =
+    SystemTools::FileTimeCompare(source, destination, &timeResult);
+  if (timeStatus.IsSuccess()) {
+    if (timeResult > 0) {
+      // Source is newer, copy it
+      return SystemTools::CopyFileAlways(source, destination);
+    } else {
+      // Source is not newer, no need to copy
+      return CopyStatus{ Status::Success(), CopyStatus::NoPath };
+    }
+  } else {
+    // Time comparison failed, be conservative and copy to ensure updates are
+    // not missed
+    return SystemTools::CopyFileAlways(source, destination);
+  }
+}
+
 #define KWSYS_ST_BUFFER 4096
 
 bool SystemTools::FilesDiffer(std::string const& source,
@@ -2585,13 +2627,29 @@
 
 SystemTools::CopyStatus SystemTools::CopyAFile(std::string const& source,
                                                std::string const& destination,
+                                               SystemTools::CopyWhen when)
+{
+  switch (when) {
+    case SystemTools::CopyWhen::Always:
+      return SystemTools::CopyFileAlways(source, destination);
+    case SystemTools::CopyWhen::OnlyIfDifferent:
+      return SystemTools::CopyFileIfDifferent(source, destination);
+    case SystemTools::CopyWhen::OnlyIfNewer:
+      return SystemTools::CopyFileIfNewer(source, destination);
+    default:
+      break;
+  }
+  // Should not reach here
+  return CopyStatus{ Status::POSIX_errno(), CopyStatus::NoPath };
+}
+
+SystemTools::CopyStatus SystemTools::CopyAFile(std::string const& source,
+                                               std::string const& destination,
                                                bool always)
 {
-  if (always) {
-    return SystemTools::CopyFileAlways(source, destination);
-  } else {
-    return SystemTools::CopyFileIfDifferent(source, destination);
-  }
+  return SystemTools::CopyAFile(source, destination,
+                                always ? CopyWhen::Always
+                                       : CopyWhen::OnlyIfDifferent);
 }
 
 /**
@@ -2599,7 +2657,8 @@
  * "destination".
  */
 Status SystemTools::CopyADirectory(std::string const& source,
-                                   std::string const& destination, bool always)
+                                   std::string const& destination,
+                                   SystemTools::CopyWhen when)
 {
   Status status;
   Directory dir;
@@ -2622,12 +2681,12 @@
         std::string fullDestPath = destination;
         fullDestPath += "/";
         fullDestPath += dir.GetFile(static_cast<unsigned long>(fileNum));
-        status = SystemTools::CopyADirectory(fullPath, fullDestPath, always);
+        status = SystemTools::CopyADirectory(fullPath, fullDestPath, when);
         if (!status.IsSuccess()) {
           return status;
         }
       } else {
-        status = SystemTools::CopyAFile(fullPath, destination, always);
+        status = SystemTools::CopyAFile(fullPath, destination, when);
         if (!status.IsSuccess()) {
           return status;
         }
@@ -2638,6 +2697,14 @@
   return status;
 }
 
+Status SystemTools::CopyADirectory(std::string const& source,
+                                   std::string const& destination, bool always)
+{
+  return SystemTools::CopyADirectory(source, destination,
+                                     always ? CopyWhen::Always
+                                            : CopyWhen::OnlyIfDifferent);
+}
+
 // return size of file; also returns zero if no file exists
 unsigned long SystemTools::FileLength(std::string const& filename)
 {
diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in
index daf6ba3..a902ab6 100644
--- a/Source/kwsys/SystemTools.hxx.in
+++ b/Source/kwsys/SystemTools.hxx.in
@@ -578,6 +578,13 @@
                                         std::string const& destination);
 
   /**
+   * Copy the source file to the destination file only
+   * if the source file is newer than the destination file.
+   */
+  static CopyStatus CopyFileIfNewer(std::string const& source,
+                                    std::string const& destination);
+
+  /**
    * Compare the contents of two files.  Return true if different
    */
   static bool FilesDiffer(std::string const& source,
@@ -658,24 +665,34 @@
   static CopyStatus CopyFileAlways(std::string const& source,
                                    std::string const& destination);
 
+  enum class CopyWhen
+  {
+    Always,
+    OnlyIfDifferent,
+    OnlyIfNewer,
+  };
+
   /**
-   * Copy a file.  If the "always" argument is true the file is always
-   * copied.  If it is false, the file is copied only if it is new or
-   * has changed.
+   * Copy a file with specified copy behavior.
    */
   static CopyStatus CopyAFile(std::string const& source,
                               std::string const& destination,
-                              bool always = true);
+                              CopyWhen when = CopyWhen::Always);
+  static CopyStatus CopyAFile(std::string const& source,
+                              std::string const& destination, bool always);
 
   /**
    * Copy content directory to another directory with all files and
-   * subdirectories.  If the "always" argument is true all files are
-   * always copied.  If it is false, only files that have changed or
-   * are new are copied.
+   * subdirectories.  The "when" argument controls when files are copied:
+   * Always: all files are always copied.
+   * OnlyIfDifferent: only files that have changed are copied.
+   * OnlyIfNewer: only files that are newer than the destination are copied.
    */
   static Status CopyADirectory(std::string const& source,
                                std::string const& destination,
-                               bool always = true);
+                               CopyWhen when = CopyWhen::Always);
+  static Status CopyADirectory(std::string const& source,
+                               std::string const& destination, bool always);
 
   /**
    * Remove a file
diff --git a/Source/kwsys/test.manifest b/Source/kwsys/test.manifest
new file mode 100644
index 0000000..2f6cefa
--- /dev/null
+++ b/Source/kwsys/test.manifest
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- Windows 10 and Windows 11 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
+      <!-- Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
+      <!-- Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
+      <!-- Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
+      <!-- Windows Vista -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
+    </application>
+  </compatibility>
+</assembly>
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index a7002e1..08e51e1 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -1160,6 +1160,94 @@
   return ret;
 }
 
+static bool CheckCopyFileIfNewer()
+{
+  bool ret = true;
+
+  // Prepare "older" files.
+  if (!writeFile("older_source.txt", "old content")) {
+    return false;
+  }
+  if (!writeFile("older_dest.txt", "old content")) {
+    return false;
+  }
+
+  // Small delay to ensure different timestamps
+#if defined(_WIN32)
+  Sleep(1125); // Sleep for 1.125 seconds on Windows
+#else
+  usleep(1125000); // Sleep for 1.125 seconds on Unix
+#endif
+
+  // Prepare "newer" files.
+  if (!writeFile("newer_source.txt", "test content")) {
+    return false;
+  }
+  if (!writeFile("newer_source2.txt", "newer content")) {
+    return false;
+  }
+  if (!writeFile("newer_dest2.txt", "new content")) {
+    return false;
+  }
+  if (!kwsys::SystemTools::MakeDirectory("newer_dir_a") ||
+      !kwsys::SystemTools::MakeDirectory("newer_dir_b")) {
+    return false;
+  }
+
+  // Test case 1: Copy when destination doesn't exist
+  if (!kwsys::SystemTools::CopyFileIfNewer("newer_source.txt",
+                                           "newer_dest1.txt")) {
+    std::cerr << "CopyFileIfNewer() failed when destination doesn't exist."
+              << std::endl;
+    ret = false;
+  } else {
+    std::string dest_content = readFile("newer_dest1.txt");
+    if (dest_content != "test content") {
+      std::cerr << "CopyFileIfNewer() incorrect content when destination "
+                   "doesn't exist."
+                << std::endl;
+      ret = false;
+    }
+  }
+
+  // Test case 2: Don't copy when source is older
+  auto copy_result =
+    kwsys::SystemTools::CopyFileIfNewer("older_source.txt", "newer_dest2.txt");
+  if (!copy_result) {
+    std::cerr << "CopyFileIfNewer() failed when source is older." << std::endl;
+    ret = false;
+  } else {
+    std::string dest_content = readFile("newer_dest2.txt");
+    if (dest_content != "new content") {
+      std::cerr
+        << "CopyFileIfNewer() should not have copied when source is older."
+        << std::endl;
+      ret = false;
+    }
+  }
+
+  // Test case 3: Copy when source is newer
+  if (!kwsys::SystemTools::CopyFileIfNewer("newer_source2.txt",
+                                           "older_dest.txt")) {
+    std::cerr << "CopyFileIfNewer() failed when source is newer." << std::endl;
+    ret = false;
+  } else {
+    std::string dest_content = readFile("older_dest.txt");
+    if (dest_content != "newer content") {
+      std::cerr << "CopyFileIfNewer() incorrect content when source is newer."
+                << std::endl;
+      ret = false;
+    }
+  }
+
+  // Test case 4: Directory to directory copy
+  if (!kwsys::SystemTools::CopyFileIfNewer("newer_dir_a/", "newer_dir_b")) {
+    ret = false;
+  }
+
+  return ret;
+}
+
 static bool CheckURLParsing()
 {
   bool ret = true;
@@ -1271,6 +1359,8 @@
 
   res &= CheckCopyFileIfDifferent();
 
+  res &= CheckCopyFileIfNewer();
+
   res &= CheckURLParsing();
 
   res &= CheckSplitString();
diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt
index 3f6ae04..7f35f04 100644
--- a/Tests/CMakeLib/CMakeLists.txt
+++ b/Tests/CMakeLib/CMakeLists.txt
@@ -24,6 +24,7 @@
   testRange.cxx
   testOptional.cxx
   testPathResolver.cxx
+  testSPDXSerializer.cxx
   testStdIo.cxx
   testString.cxx
   testStringAlgorithms.cxx
diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx
index 4bf6a40..789ab12 100644
--- a/Tests/CMakeLib/testArgumentParser.cxx
+++ b/Tests/CMakeLib/testArgumentParser.cxx
@@ -16,9 +16,17 @@
 #include "testCommon.h"
 
 namespace {
-
-struct Result : public ArgumentParser::ParseResult
+struct Result : ArgumentParser::ParseResult
 {
+  struct SubResult : ParseResult
+  {
+    ArgumentParser::NonEmpty<std::string> SubCommand;
+    bool SubOption = false;
+    ArgumentParser::NonEmpty<std::string> SubString;
+    ArgumentParser::NonEmpty<std::vector<std::string>> SubList;
+    std::vector<cm::string_view> ParsedKeywords;
+  };
+
   bool Option1 = false;
   bool Option2 = false;
 
@@ -83,6 +91,9 @@
                             : ArgumentParser::Continue::No;
   }
 
+  cm::optional<SubResult> Sub;
+  ArgumentParser::NonEmpty<std::string> Parent;
+
   ArgumentParser::Maybe<std::string> UnboundMaybe{ 'u', 'n', 'b', 'o',
                                                    'u', 'n', 'd' };
   ArgumentParser::MaybeEmpty<std::vector<std::string>> UnboundMaybeEmpty{
@@ -131,7 +142,12 @@
   "FUNC_3", "foo", "bar",    // callback with list arg ...
   "FUNC_4a", "foo", "ign4",  // callback with keyword-dependent arg count
   "FUNC_4b", "bar", "zot",   // callback with keyword-dependent arg count
-  /* clang-format on */
+  "SUB_CMD",  "foo",         // switch to subparser and set Sub::SUB_CMD to foo
+  "SUB_OPTION",              // subparser option
+  "SUB_STRING", "sub_value", // subparser string
+  "SUB_LIST", "a", "b", "c", // subparser list
+  // Return to main parser (simulate another main option if needed)
+  "PARENT", "value",
 };
 
 struct ResultTrailingPos : public ArgumentParser::ParseResult
@@ -189,8 +205,15 @@
     "FUNC_3",
     "FUNC_4a",
     "FUNC_4b",
+    "SUB_CMD",
+    "PARENT",
     /* clang-format on */
   };
+
+  static std::vector<cm::string_view> subParsedKeywords = {
+    "SUB_CMD", "SUB_OPTION", "SUB_STRING", "SUB_LIST"
+  };
+
   static std::map<std::string, std::vector<std::string>> const func2map = {
     { "FUNC_2a", { "foo" } }, { "FUNC_2b", { "bar", "zot" } }
   };
@@ -257,6 +280,14 @@
   ASSERT_TRUE(result.UnboundNonEmpty == unbound);
   ASSERT_TRUE(result.UnboundNonEmptyStr == "unbound");
 
+  ASSERT_TRUE(result.Sub->SubCommand == "foo");
+  ASSERT_TRUE(result.Sub->SubOption);
+  ASSERT_TRUE(result.Sub->SubString == "sub_value");
+  ASSERT_TRUE(result.Sub->SubList ==
+              std::vector<std::string>({ "a", "b", "c" }));
+  ASSERT_TRUE(result.Parent == "value");
+
+  ASSERT_TRUE(result.Sub->ParsedKeywords == subParsedKeywords);
   ASSERT_TRUE(result.ParsedKeywords == parsedKeywords);
 
   ASSERT_TRUE(result.GetKeywordErrors().size() == keywordErrors.size());
@@ -292,6 +323,8 @@
 bool testArgumentParserDynamic()
 {
   Result result;
+  result.Sub = Result::SubResult();
+
   std::vector<std::string> unparsedArguments;
 
   std::function<ArgumentParser::Continue(cm::string_view, cm::string_view)>
@@ -305,6 +338,13 @@
   ASSERT_TRUE(parserDynamic.HasKeyword("OPTION_1"_s));
   ASSERT_TRUE(!parserDynamic.HasKeyword("NOT_AN_OPTION"_s));
 
+  auto subParser = cmArgumentParser<void>{}
+                     .Bind("SUB_CMD"_s, result.Sub->SubCommand)
+                     .Bind("SUB_OPTION"_s, result.Sub->SubOption)
+                     .Bind("SUB_STRING"_s, result.Sub->SubString)
+                     .Bind("SUB_LIST"_s, result.Sub->SubList)
+                     .BindParsedKeywords(result.Sub->ParsedKeywords);
+
   static_cast<ArgumentParser::ParseResult&>(result) =
     cmArgumentParser<void>{}
       .Bind(0, result.Pos0)
@@ -349,6 +389,8 @@
             })
       .Bind("FUNC_4a"_s, func4)
       .Bind("FUNC_4b"_s, func4)
+      .BindSubParser("SUB_CMD"_s, subParser, result.Sub)
+      .Bind("PARENT"_s, result.Parent)
       .BindParsedKeywords(result.ParsedKeywords)
       .Parse(args, &unparsedArguments);
 
@@ -378,7 +420,17 @@
 };
 
 #define BIND_ALL(name, resultType)                                            \
-  static auto const name =                                                    \
+  /* Define the sub-parser first */                                           \
+  static auto sub##name =                                                     \
+    cmArgumentParser<resultType::SubResult>{}                                 \
+      .Bind("SUB_CMD"_s, &resultType::SubResult::SubCommand)                  \
+      .Bind("SUB_OPTION"_s, &resultType::SubResult::SubOption)                \
+      .Bind("SUB_STRING"_s, &resultType::SubResult::SubString)                \
+      .Bind("SUB_LIST"_s, &resultType::SubResult::SubList)                    \
+      .BindParsedKeywords(&resultType::SubResult::ParsedKeywords);            \
+                                                                              \
+  /* Define the main parser, which uses the sub-parser */                     \
+  static const auto name =                                                    \
     cmArgumentParser<resultType>{}                                            \
       .Bind(0, &resultType::Pos0)                                             \
       .Bind(1, &resultType::Pos1)                                             \
@@ -411,7 +463,9 @@
               -> ArgumentParser::Continue { return result.Func3(arg); })      \
       .Bind("FUNC_4a"_s, parserStaticFunc4)                                   \
       .Bind("FUNC_4b"_s, parserStaticFunc4)                                   \
-      .BindParsedKeywords(&resultType::ParsedKeywords)
+      .BindSubParser("SUB_CMD"_s, sub##name, &resultType::Sub)                \
+      .Bind("PARENT"_s, &resultType::Parent)                                  \
+      .BindParsedKeywords(&resultType::ParsedKeywords);
 
 BIND_ALL(parserStatic, Result);
 BIND_ALL(parserDerivedStatic, Derived);
@@ -484,11 +538,10 @@
 
   ArgumentParser::NonEmpty<std::vector<std::string>> nonEmptyVecStr;
   nonEmptyVecStr = std::vector<std::string>{ "" };
-
   return true;
 }
 
-} // namespace
+}
 
 int testArgumentParser(int /*unused*/, char* /*unused*/[])
 {
diff --git a/Tests/CMakeLib/testCommon.h b/Tests/CMakeLib/testCommon.h
index b7379d5..78c6f24 100644
--- a/Tests/CMakeLib/testCommon.h
+++ b/Tests/CMakeLib/testCommon.h
@@ -29,7 +29,7 @@
 
 namespace {
 
-inline int runTests(std::initializer_list<std::function<bool()>> const& tests,
+inline int runTests(std::initializer_list<std::function<bool()>> tests,
                     bool const fail_fast = true)
 {
   int result = 0;
diff --git a/Tests/CMakeLib/testDebuggerAdapter.cxx b/Tests/CMakeLib/testDebuggerAdapter.cxx
index c5ad8b3..cc7c71a 100644
--- a/Tests/CMakeLib/testDebuggerAdapter.cxx
+++ b/Tests/CMakeLib/testDebuggerAdapter.cxx
@@ -83,16 +83,13 @@
 
   auto connection = std::make_shared<DebuggerLocalConnection>();
   std::unique_ptr<dap::Session> client = dap::Session::create();
-  client->registerHandler([&](dap::InitializedEvent const& e) {
-    (void)e;
+  client->registerHandler([&](dap::InitializedEvent /*unused*/) {
     initializedEventReceivedPromise.set_value(true);
   });
-  client->registerHandler([&](dap::ExitedEvent const& e) {
-    (void)e;
+  client->registerHandler([&](dap::ExitedEvent /*unused*/) {
     exitedEventReceivedPromise.set_value(true);
   });
-  client->registerHandler([&](dap::TerminatedEvent const& e) {
-    (void)e;
+  client->registerHandler([&](dap::TerminatedEvent const& /*unused*/) {
     terminatedEventReceivedPromise.set_value(true);
   });
   client->registerHandler([&](dap::ThreadEvent const& e) {
diff --git a/Tests/CMakeLib/testDebuggerAdapterPipe.cxx b/Tests/CMakeLib/testDebuggerAdapterPipe.cxx
index 15dc32b..d7c4134 100644
--- a/Tests/CMakeLib/testDebuggerAdapterPipe.cxx
+++ b/Tests/CMakeLib/testDebuggerAdapterPipe.cxx
@@ -76,16 +76,13 @@
 #endif
 
   std::unique_ptr<dap::Session> client = dap::Session::create();
-  client->registerHandler([&](dap::InitializedEvent const& e) {
-    (void)e;
+  client->registerHandler([&](dap::InitializedEvent /*unused*/) {
     initializedEventReceivedPromise.set_value(true);
   });
-  client->registerHandler([&](dap::ExitedEvent const& e) {
-    (void)e;
+  client->registerHandler([&](dap::ExitedEvent /*unused*/) {
     exitedEventReceivedPromise.set_value(true);
   });
-  client->registerHandler([&](dap::TerminatedEvent const& e) {
-    (void)e;
+  client->registerHandler([&](dap::TerminatedEvent const& /*unused*/) {
     terminatedEventReceivedPromise.set_value(true);
   });
   client->registerHandler([&](dap::ThreadEvent const& e) {
diff --git a/Tests/CMakeLib/testSPDXSerializer.cxx b/Tests/CMakeLib/testSPDXSerializer.cxx
new file mode 100644
index 0000000..b8ab923
--- /dev/null
+++ b/Tests/CMakeLib/testSPDXSerializer.cxx
@@ -0,0 +1,649 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <cm/optional>
+#include <cm/type_traits>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+#include "cmSPDXSerializer.h"
+
+namespace {
+
+std::string const nonOptional(R"================({
+  "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
+  "@graph": [
+    {
+      "@id": "_:contentIdentifier_0",
+      "contentIdentifierType": "INVALID_CONTENT_IDENTIFIER_TYPE_ID",
+      "contentIdentifierValue": "",
+      "type": "ContentIdentifier"
+    },
+    {
+      "@id": "_:creationInfo_0",
+      "created": "",
+      "createdBy": [],
+      "type": "CreationInfo"
+    },
+    {
+      "@id": "_:creationInfo_1",
+      "created": "",
+      "createdBy": [],
+      "type": "CreationInfo"
+    },
+    {
+      "@id": "_:dictionaryEntry_0",
+      "key": "",
+      "type": "DictionaryEntry"
+    },
+    {
+      "@id": "_:externalIdentifier_0",
+      "externalIdentifierType": "INVALID_EXTERNAL_IDENTIFIER_TYPE_ID",
+      "identifier": "",
+      "type": "ExternalIdentifier"
+    },
+    {
+      "@id": "_:externalMap_0",
+      "externalSpdxId": "",
+      "type": "ExternalMap"
+    },
+    {
+      "@id": "_:externalRef_0",
+      "type": "ExternalRef"
+    },
+    {
+      "@id": "_:hash_0",
+      "algorithm": "INVALID_HASH_TYPE_ID",
+      "hashValue": "",
+      "type": "Hash"
+    },
+    {
+      "@id": "_:namespaceMap_0",
+      "namespace": "",
+      "prefix": "",
+      "type": "NamespaceMap"
+    },
+    {
+      "@id": "_:packageVerificationCode_0",
+      "algorithm": "INVALID_HASH_TYPE_ID",
+      "hashValue": "",
+      "type": "PackageVerificationCode"
+    },
+    {
+      "@id": "_:positiveIntegerRange_0",
+      "beginIntegerRange": 0,
+      "endIntegerRange": 0,
+      "type": "PositiveIntegerRange"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd0",
+      "type": "Agent"
+    },
+    {
+      "annotationType": "INVALID_ANNOTATION_TYPE_ID",
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd1",
+      "subject": "",
+      "type": "Annotation"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd10",
+      "type": "SpdxDocument"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd11",
+      "type": "Tool"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd12",
+      "type": "File"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd13",
+      "type": "Package"
+    },
+    {
+      "context": "",
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd14",
+      "type": "Sbom"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "snippetFromFile": "",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd15",
+      "type": "Snippet"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "licenseExpression": "",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd16",
+      "type": "LicenseExpression"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "licenseText": "",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd17",
+      "type": "SimpleLicensingText"
+    },
+    {
+      "context": "",
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd2",
+      "type": "Bom"
+    },
+    {
+      "context": "",
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd3",
+      "type": "Bundle"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd4",
+      "type": "IndividualElement"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "from": "",
+      "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd5",
+      "to": [],
+      "type": "LifecycleScopedRelationship"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd6",
+      "type": "Organization"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd7",
+      "type": "Person"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "from": "",
+      "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd8",
+      "to": [],
+      "type": "Relationship"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd9",
+      "type": "SoftwareAgent"
+    }
+  ]
+})================");
+
+std::string const Optional(R"================({
+  "@context": "https://spdx.org/rdf/3.0.1/spdx-context.jsonld",
+  "@graph": [
+    {
+      "@id": "_:contentIdentifier_0",
+      "contentIdentifierType": "gitoid",
+      "contentIdentifierValue": "ContentIdentifierValue",
+      "type": "ContentIdentifier"
+    },
+    {
+      "@id": "_:creationInfo_0",
+      "created": "",
+      "createdBy": [],
+      "type": "CreationInfo"
+    },
+    {
+      "@id": "_:creationInfo_1",
+      "Comment": "Comment",
+      "created": "Created",
+      "createdBy": [
+        "testRef"
+      ],
+      "createdUsing": [
+        "testRef"
+      ],
+      "type": "CreationInfo"
+    },
+    {
+      "@id": "_:dictionaryEntry_0",
+      "key": "Key",
+      "type": "DictionaryEntry",
+      "value": "Value"
+    },
+    {
+      "@id": "_:externalIdentifier_0",
+      "comment": "Comment",
+      "externalIdentifierType": "other",
+      "identifier": "Identifier",
+      "identifierLocator": [
+        "IdentifierLocator"
+      ],
+      "issuingAuthority": "IssuingAuthority",
+      "type": "ExternalIdentifier"
+    },
+    {
+      "@id": "_:externalMap_0",
+      "definingArtifact": "testRef",
+      "externalSpdxId": "ExternalSpdxId",
+      "integrityMethod": [
+        "testRef"
+      ],
+      "locationHint": "LocationHint",
+      "type": "ExternalMap"
+    },
+    {
+      "@id": "_:externalRef_0",
+      "comment": "Comment",
+      "contentType": "ContentType",
+      "externalRefType": "other",
+      "locator": [
+        "Locator"
+      ],
+      "type": "ExternalRef"
+    },
+    {
+      "@id": "_:hash_0",
+      "algorithm": "other",
+      "hashValue": "HashValue",
+      "type": "Hash"
+    },
+    {
+      "@id": "_:namespaceMap_0",
+      "namespace": "Namespace",
+      "prefix": "Namespace",
+      "type": "NamespaceMap"
+    },
+    {
+      "@id": "_:packageVerificationCode_0",
+      "algorithm": "other",
+      "hashValue": "HashValue",
+      "type": "PackageVerificationCode"
+    },
+    {
+      "@id": "_:positiveIntegerRange_0",
+      "beginIntegerRange": 1,
+      "endIntegerRange": 2,
+      "type": "PositiveIntegerRange"
+    },
+    {
+      "comment": "Comment",
+      "creationInfo": "_:creationInfo_0",
+      "description": "Description",
+      "extension": [
+        "testRef"
+      ],
+      "externalIdentifier": [
+        "testRef"
+      ],
+      "externalRef": [
+        "testRef"
+      ],
+      "name": "Name",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd0",
+      "summary": "Summary",
+      "type": "Agent",
+      "verifiedUsing": [
+        "testRef"
+      ]
+    },
+    {
+      "annotationType": "other",
+      "contentType": "ContentType",
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd1",
+      "statement": "Statement",
+      "subject": "testRef",
+      "type": "Annotation"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "dataLicense": "testRef",
+      "externalMap": "testRef",
+      "namespaceMap": "testRef",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd10",
+      "type": "SpdxDocument"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd11",
+      "type": "Tool"
+    },
+    {
+      "additionalPurpose": [
+        "other"
+      ],
+      "attributionText": "AttributionText",
+      "contentIdentifier": "testRef",
+      "contentType": "ContentType",
+      "copyrightText": "CopyrightText",
+      "creationInfo": "_:creationInfo_0",
+      "fileKind": "file",
+      "primaryPurpose": "file",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd12",
+      "type": "File"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "downloadLocation": "DownloadLocation",
+      "homePage": "HomePage",
+      "packageUrl": "PackageUrl",
+      "packageVersion": "PackageVersion",
+      "sourceInfo": "SourceInfo",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd13",
+      "type": "Package"
+    },
+    {
+      "context": "",
+      "creationInfo": "_:creationInfo_0",
+      "sbomType": [
+        "build"
+      ],
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd14",
+      "type": "Sbom"
+    },
+    {
+      "byteRange": "testRef",
+      "creationInfo": "_:creationInfo_0",
+      "lineRange": "testRef",
+      "snippetFromFile": "testRef",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd15",
+      "type": "Snippet"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "customIdToUri": [
+        "testRef"
+      ],
+      "licenseExpression": "LicenseExpression",
+      "licenseListVersion": "LicenseListVersion",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd16",
+      "type": "LicenseExpression"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "licenseText": "LicenseText",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd17",
+      "type": "SimpleLicensingText"
+    },
+    {
+      "context": "Context",
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd2",
+      "type": "Bom"
+    },
+    {
+      "context": "",
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd3",
+      "type": "Bundle"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd4",
+      "type": "IndividualElement"
+    },
+    {
+      "completeness": "noAssertion",
+      "creationInfo": "_:creationInfo_0",
+      "endTime": "EndTime",
+      "from": "testRef",
+      "relationshipType": "other",
+      "scope": "other",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd5",
+      "startTime": "StartTime",
+      "to": [
+        "testRef"
+      ],
+      "type": "LifecycleScopedRelationship"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd6",
+      "type": "Organization"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd7",
+      "type": "Person"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "from": "",
+      "relationshipType": "INVALID_RELATIONSHIP_TYPE_ID",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd8",
+      "to": [],
+      "type": "Relationship"
+    },
+    {
+      "creationInfo": "_:creationInfo_0",
+      "spdxId": "https://cmake.org/testSPDXSerialization-gnrtd9",
+      "type": "SoftwareAgent"
+    }
+  ]
+})================");
+}
+
+int testNonOptional()
+{
+  cmSPDXSimpleGraph graph("https://cmake.org/testSPDXSerialization-gnrtd");
+
+  // Core
+  graph.insert<cmSPDXAgent>();
+  graph.insert<cmSPDXAnnotation>();
+  graph.insert<cmSPDXBom>();
+  graph.insert<cmSPDXBundle>();
+  graph.insert<cmSPDXCreationInfo>();
+  graph.insert<cmSPDXDictionaryEntry>();
+  graph.insert<cmSPDXExternalIdentifier>();
+  graph.insert<cmSPDXExternalMap>();
+  graph.insert<cmSPDXExternalRef>();
+  graph.insert<cmSPDXHash>();
+  graph.insert<cmSPDXIndividualElement>();
+  graph.insert<cmSPDXLifecycleScopedRelationship>();
+  graph.insert<cmSPDXNamespaceMap>();
+  graph.insert<cmSPDXOrganization>();
+  graph.insert<cmSPDXPackageVerificationCode>();
+  graph.insert<cmSPDXPerson>();
+  graph.insert<cmSPDXPositiveIntegerRange>();
+  graph.insert<cmSPDXRelationship>();
+  graph.insert<cmSPDXSoftwareAgent>();
+  graph.insert<cmSPDXSpdxDocument>();
+  graph.insert<cmSPDXTool>();
+
+  // Software
+  graph.insert<cmSPDXContentIdentifier>();
+  graph.insert<cmSPDXFile>();
+  graph.insert<cmSPDXPackage>();
+  graph.insert<cmSPDXSbom>();
+  graph.insert<cmSPDXSnippet>();
+
+  // SimpleLicensing
+  graph.insert<cmSPDXLicenseExpression>();
+  graph.insert<cmSPDXSimpleLicensingText>();
+
+  Json::Value root;
+  Json::Reader().parse(nonOptional.c_str(), root);
+
+  std::cout << "NonOptional SPDX:";
+  std::cout << "\nConstructed Graph: " << graph.toJsonLD().toStyledString();
+  std::cout << "\nComparison Graph:" << root.toStyledString() << "\n";
+
+  // Convert to string to disregard differences in number signedness
+  return root.toStyledString() == graph.toJsonLD().toStyledString();
+};
+
+int testOptional()
+{
+  cmSPDXSimpleGraph graph("https://cmake.org/testSPDXSerialization-gnrtd");
+
+  cmSPDXIdentifierReference ident("testRef");
+
+  // Core
+  auto& agent = graph.insert<cmSPDXAgent>();
+  agent.Comment = "Comment";
+  agent.Description = "Description";
+  agent.Extension.emplace().push_back(ident);
+  agent.ExternalIdentifier.emplace().push_back(ident);
+  agent.ExternalRef.emplace().push_back(ident);
+  agent.Name = "Name";
+  agent.Summary = "Summary";
+  agent.VerifiedUsing.emplace().push_back(ident);
+
+  auto& annotation = graph.insert<cmSPDXAnnotation>();
+  annotation.AnnotationType = cmSPDXAnnotationType::OTHER;
+  annotation.ContentType = "ContentType";
+  annotation.Statement = "Statement";
+  annotation.Subject = ident;
+
+  auto& bom = graph.insert<cmSPDXBom>();
+  bom.Context = "Context";
+
+  graph.insert<cmSPDXBundle>();
+
+  auto& creationInfo = graph.insert<cmSPDXCreationInfo>();
+  creationInfo.Comment = "Comment";
+  creationInfo.Created = "Created";
+  creationInfo.CreatedBy.push_back(ident);
+  creationInfo.CreatedUsing.emplace().push_back(ident);
+
+  auto& dictionaryEntry = graph.insert<cmSPDXDictionaryEntry>();
+  dictionaryEntry.Key = "Key";
+  dictionaryEntry.Value = "Value";
+
+  auto& externalIdentifier = graph.insert<cmSPDXExternalIdentifier>();
+  externalIdentifier.Comment = "Comment";
+  externalIdentifier.ExternalIdentifierType =
+    cmSPDXExternalIdentifierType::OTHER;
+  externalIdentifier.Identifier = "Identifier";
+  externalIdentifier.IdentifierLocator.emplace().push_back(
+    "IdentifierLocator");
+  externalIdentifier.IssuingAuthority = "IssuingAuthority";
+
+  auto& externalMap = graph.insert<cmSPDXExternalMap>();
+  externalMap.DefiningArtifact = ident;
+  externalMap.ExternalSpdxId = "ExternalSpdxId";
+  externalMap.LocationHint = "LocationHint";
+  externalMap.IntegrityMethod.emplace().push_back(ident);
+
+  auto& externalRef = graph.insert<cmSPDXExternalRef>();
+  externalRef.Comment = "Comment";
+  externalRef.ContentType = "ContentType";
+  externalRef.ExternalRefType = cmSPDXExternalRefType::OTHER;
+  externalRef.Locator.emplace().push_back("Locator");
+
+  auto& hash = graph.insert<cmSPDXHash>();
+  hash.Algorithm = cmSPDXHashAlgorithm::OTHER;
+  hash.HashValue = "HashValue";
+
+  graph.insert<cmSPDXIndividualElement>();
+
+  auto& lifecycleScopedRelationship =
+    graph.insert<cmSPDXLifecycleScopedRelationship>();
+  lifecycleScopedRelationship.Completeness =
+    cmSPDXRelationshipCompletenessType::NO_ASSERTION;
+  lifecycleScopedRelationship.EndTime = "EndTime";
+  lifecycleScopedRelationship.From = ident;
+  lifecycleScopedRelationship.RelationshipType = cmSPDXRelationshipType::OTHER;
+  lifecycleScopedRelationship.StartTime = "StartTime";
+  lifecycleScopedRelationship.To.push_back(ident);
+  lifecycleScopedRelationship.Scope = cmSPDXLifecycleScopeType::OTHER;
+
+  auto& namespaceMap = graph.insert<cmSPDXNamespaceMap>();
+  namespaceMap.Namespace = "Namespace";
+  namespaceMap.Prefix = "Prefix";
+
+  graph.insert<cmSPDXOrganization>();
+
+  auto& packageVerificationCode =
+    graph.insert<cmSPDXPackageVerificationCode>();
+  packageVerificationCode.Algorithm = cmSPDXHashAlgorithm::OTHER;
+  packageVerificationCode.HashValue = "HashValue";
+  packageVerificationCode.PackageVerificationCodeExcludedFile.emplace()
+    .push_back("PacakgeVerificationCodeExcludeFile");
+
+  graph.insert<cmSPDXPerson>();
+
+  auto& positiveIntegerRange = graph.insert<cmSPDXPositiveIntegerRange>();
+  positiveIntegerRange.BeginIntegerRange = 1;
+  positiveIntegerRange.EndIntegerRange = 2;
+
+  graph.insert<cmSPDXRelationship>();
+
+  graph.insert<cmSPDXSoftwareAgent>();
+
+  auto& spdxDocument = graph.insert<cmSPDXSpdxDocument>();
+  spdxDocument.DataLicense = ident;
+  spdxDocument.ExternalMap = ident;
+  spdxDocument.NamespaceMap = ident;
+
+  graph.insert<cmSPDXTool>();
+
+  // Software
+  auto& contentIdentifier = graph.insert<cmSPDXContentIdentifier>();
+  contentIdentifier.ContentIdentifierType =
+    cmSPDXContentIdentifierType::GITOID;
+  contentIdentifier.ContentIdentifierValue = "ContentIdentifierValue";
+
+  auto& file = graph.insert<cmSPDXFile>();
+  file.AdditionalPurpose.emplace().push_back(cmSPDXSoftwarePurpose::OTHER);
+  file.AttributionText = "AttributionText";
+  file.ContentIdentifier = ident;
+  file.CopyrightText = "CopyrightText";
+  file.PrimaryPurpose = cmSPDXSoftwarePurpose::FILE;
+  file.ContentType = "ContentType";
+  file.FileKind = cmSPDXFileKindType::FILE;
+
+  auto& package = graph.insert<cmSPDXPackage>();
+  package.DownloadLocation = "DownloadLocation";
+  package.HomePage = "HomePage";
+  package.PackageUrl = "PackageUrl";
+  package.PackageVersion = "PackageVersion";
+  package.SourceInfo = "SourceInfo";
+
+  auto& sbom = graph.insert<cmSPDXSbom>();
+  sbom.SbomType.emplace().push_back(cmSPDXSbomType::BUILD);
+
+  auto& snippet = graph.insert<cmSPDXSnippet>();
+  snippet.ByteRange = ident;
+  snippet.LineRange = ident;
+  snippet.SnippetFromFile = ident;
+
+  // SimpleLicensing
+  auto& licenseExpression = graph.insert<cmSPDXLicenseExpression>();
+  licenseExpression.CustomIdToUri.emplace().push_back(ident);
+  licenseExpression.LicenseExpression = "LicenseExpression";
+  licenseExpression.LicenseListVersion = "LicenseListVersion";
+
+  auto& simpleLicensingText = graph.insert<cmSPDXSimpleLicensingText>();
+  simpleLicensingText.LicenseText = "LicenseText";
+
+  Json::Value root;
+  Json::Reader().parse(Optional.c_str(), root);
+
+  std::cout << "Optional SPDX:";
+  std::cout << "\nConstructed Graph: " << graph.toJsonLD().toStyledString();
+  std::cout << "\nComparison Graph:" << root.toStyledString() << "\n";
+
+  // Convert to string to disregard differences in number signedness
+  return root.toStyledString() == graph.toJsonLD().toStyledString();
+};
+
+int testSPDXSerializer(int /* argc */, char* /* argv */[])
+{
+  if (!testNonOptional())
+    return -1;
+
+  if (!testOptional())
+    return -1;
+
+  return 0;
+}
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 15a1e2c..fed2c80 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -36,6 +36,8 @@
 set(TEST_HOME "${CMake_BINARY_DIR}/Tests/CMakeFiles/TestHome")
 set(TEST_CONFIG_ENV_CODE "# Isolate tests from user-wide configuration.
 set(ENV{CMAKE_CONFIG_DIR} \"${TEST_HOME}/.config/cmake\")\n")
+set(TEST_INSTRUMENTATION_ENV_CODE "# Isolate tests from CTEST_USE_INSTRUMENTATION var
+unset(ENV{CTEST_USE_INSTRUMENTATION})\n")
 file(MAKE_DIRECTORY "${TEST_HOME}/.config/cmake")
 
 # Fake a user home directory to avoid polluting the real one.
@@ -50,6 +52,13 @@
 ")
 endif()
 
+# Suppress generator deprecation warnings in test suite.
+if(CMAKE_GENERATOR MATCHES "^Visual Studio 14 2015")
+  set(TEST_WARN_VS_CODE "set(ENV{CMAKE_WARN_VS14} OFF)")
+else()
+  set(TEST_WARN_VS_CODE "")
+endif()
+
 # 3.9 or later provides a definitive answer to whether we are multi-config
 # through a global property. Prior to 3.9, CMAKE_CONFIGURATION_TYPES being set
 # is assumed to mean multi-config, but developers might modify it so it is
@@ -586,11 +595,11 @@
   if(NOT DEFINED CMake_TEST_Qt4)
     set(CMake_TEST_Qt4 1)
   endif()
-  if(CMake_TEST_Qt4 AND NOT QT4_FOUND)
+  if(CMake_TEST_Qt4 AND NOT Qt4_FOUND)
     find_package(Qt4 QUIET)
   endif()
 
-  if(CMake_TEST_Qt4 AND QT4_FOUND)
+  if(CMake_TEST_Qt4 AND Qt4_FOUND)
     # test whether the Qt4 which has been found works, on some machines
     # which run nightly builds there were errors like "wrong file format"
     # for libQtCore.so. So first check it works, and only if it does add
diff --git a/Tests/CMakeOnly/AllFindModules/CMakeLists.txt b/Tests/CMakeOnly/AllFindModules/CMakeLists.txt
index 8e70eb1..a95fc98 100644
--- a/Tests/CMakeOnly/AllFindModules/CMakeLists.txt
+++ b/Tests/CMakeOnly/AllFindModules/CMakeLists.txt
@@ -44,7 +44,7 @@
 endforeach()
 
 # Qt4 is not present, so we can check Qt3
-if (NOT QT4_FOUND)
+if (NOT Qt4_FOUND)
     set(DESIRED_QT_VERSION 3)
     foreach(FIND_MODULE ${NO_QT4_MODULES} "Qt")
         do_find(${FIND_MODULE})
@@ -90,15 +90,46 @@
 # If any of these modules reported that it was found a version number should have been
 # reported.
 
-foreach(VTEST ALSA ARMADILLO BZIP2 CUPS CURL EXPAT FREETYPE GETTEXT GIT HG
-        HSPELL ICOTOOL JASPER LIBLZMA LIBXML2 LIBXSLT LTTNGUST PERL PKG_CONFIG
-        PostgreSQL TIFF ZLIB)
-    check_version_string(${VTEST} ${VTEST}_VERSION_STRING)
+foreach(
+  VTEST
+    ALSA ARMADILLO
+    BZIP2
+    CUPS CURL
+    EXPAT
+    FREETYPE
+    GETTEXT GIT GNUTLS
+    HG HSPELL
+    ICOTOOL
+    JASPER
+    LIBLZMA LIBXML2 LIBXSLT LTTNGUST
+    PERL PKG_CONFIG PNG PostgreSQL
+    SDL
+    TIFF
+    ZLIB
+)
+  check_version_string(${VTEST} ${VTEST}_VERSION_STRING)
 endforeach()
 
-foreach(VTEST BISON Boost BZIP2 CUDA DOXYGEN FLEX GIF GTK2
-    HDF5 JPEG LibArchive LIBLZMA OPENSCENEGRAPH Ruby RUBY SWIG Protobuf ZLIB)
-    check_version_string(${VTEST} ${VTEST}_VERSION)
+foreach(
+  VTEST
+    ALSA Armadillo
+    BISON Boost BZip2 BZIP2
+    CUDA Cups
+    DevIL Doxygen DOXYGEN
+    EXPAT
+    FLEX Freetype
+    Gettext GIF GnuTLS GNUTLS GTK2
+    HDF5
+    Jasper JPEG
+    LibArchive LibLZMA LIBLZMA LibXml2 LibXslt LTTngUST
+    OpenSceneGraph OPENSCENEGRAPH OpenSSL OPENSSL
+    Perl PerlLibs PNG PostgreSQL Protobuf
+    Ruby RUBY
+    SDL SWIG
+    TIFF
+    ZLIB
+)
+  check_version_string(${VTEST} ${VTEST}_VERSION)
 endforeach()
 
 check_version_string(PYTHONINTERP PYTHON_VERSION_STRING)
diff --git a/Tests/CTestUpdateGIT.cmake.in b/Tests/CTestUpdateGIT.cmake.in
index 5e3448b..4921304 100644
--- a/Tests/CTestUpdateGIT.cmake.in
+++ b/Tests/CTestUpdateGIT.cmake.in
@@ -19,6 +19,8 @@
 set(AUTHOR_CONFIG "[user]
 \tname = Test Author
 \temail = testauthor@cmake.org
+[commit]
+\tgpgsign = false
 ")
 
 #-----------------------------------------------------------------------------
diff --git a/Tests/Complex/CMakeLists.txt b/Tests/Complex/CMakeLists.txt
index 0ea2970..8a064a4 100644
--- a/Tests/Complex/CMakeLists.txt
+++ b/Tests/Complex/CMakeLists.txt
@@ -4,6 +4,8 @@
 cmake_minimum_required(VERSION 3.10)
 project (Complex)
 
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Inform the test if the debug configuration is getting built.
 string(APPEND CMAKE_C_FLAGS_RELEASE " -DCOMPLEX_NDEBUG")
 string(APPEND CMAKE_CXX_FLAGS_RELEASE " -DCOMPLEX_NDEBUG")
diff --git a/Tests/ComplexOneConfig/CMakeLists.txt b/Tests/ComplexOneConfig/CMakeLists.txt
index 3dc4eca..4b00e5d 100644
--- a/Tests/ComplexOneConfig/CMakeLists.txt
+++ b/Tests/ComplexOneConfig/CMakeLists.txt
@@ -4,6 +4,8 @@
 cmake_minimum_required(VERSION 3.10)
 project (Complex)
 
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Inform the test if the debug configuration is getting built.
 string(APPEND CMAKE_C_FLAGS_RELEASE " -DCOMPLEX_NDEBUG")
 string(APPEND CMAKE_CXX_FLAGS_RELEASE " -DCOMPLEX_NDEBUG")
diff --git a/Tests/EnforceConfig.cmake.in b/Tests/EnforceConfig.cmake.in
index 78dea00..6d634d6 100644
--- a/Tests/EnforceConfig.cmake.in
+++ b/Tests/EnforceConfig.cmake.in
@@ -45,3 +45,4 @@
 @TEST_CONFIG_ENV_CODE@
 @TEST_HOME_ENV_CODE@
 @TEST_WARN_VS_CODE@
+@TEST_INSTRUMENTATION_ENV_CODE@
diff --git a/Tests/ExternalProjectUpdate/CMakeLists.txt b/Tests/ExternalProjectUpdate/CMakeLists.txt
index cbddd2f..2339d30 100644
--- a/Tests/ExternalProjectUpdate/CMakeLists.txt
+++ b/Tests/ExternalProjectUpdate/CMakeLists.txt
@@ -95,6 +95,7 @@
     GIT_TAG ${TEST_GIT_TAG}
     GIT_CONFIG "user.email=testauthor@cmake.org"
                "user.name=testauthor"
+               "commit.gpgsign=false"
     CMAKE_GENERATOR "${CMAKE_GENERATOR}"
     CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
     INSTALL_COMMAND ""
diff --git a/Tests/FindALSA/Test/CMakeLists.txt b/Tests/FindALSA/Test/CMakeLists.txt
index 2829740..8ca7f99 100644
--- a/Tests/FindALSA/Test/CMakeLists.txt
+++ b/Tests/FindALSA/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(ALSA REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_ALSA_VERSION="${ALSA_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_ALSA_VERSION="${ALSA_VERSION}")
 
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt ALSA::ALSA)
diff --git a/Tests/FindBZip2/Test/CMakeLists.txt b/Tests/FindBZip2/Test/CMakeLists.txt
index 281339a..bffb652 100644
--- a/Tests/FindBZip2/Test/CMakeLists.txt
+++ b/Tests/FindBZip2/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(BZip2 REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_BZip2_VERSION="${BZip2_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_BZip2_VERSION="${BZip2_VERSION}")
 
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt BZip2::BZip2)
diff --git a/Tests/FindBZip2/Test/main.c b/Tests/FindBZip2/Test/main.c
index b3cf34b..0dc27b3 100644
--- a/Tests/FindBZip2/Test/main.c
+++ b/Tests/FindBZip2/Test/main.c
@@ -1,6 +1,7 @@
 #include <bzlib.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 int main(void)
 {
@@ -19,5 +20,9 @@
 
   remove("test.bzip2");
 
-  return 0;
+  printf("Found BZip2 version %s, expected version %s\n", BZ2_bzlibVersion(),
+         CMAKE_EXPECTED_BZip2_VERSION);
+
+  return strncmp(BZ2_bzlibVersion(), CMAKE_EXPECTED_BZip2_VERSION,
+                 strlen(CMAKE_EXPECTED_BZip2_VERSION));
 }
diff --git a/Tests/FindCups/Test/CMakeLists.txt b/Tests/FindCups/Test/CMakeLists.txt
index 9e90553..e17acbb 100644
--- a/Tests/FindCups/Test/CMakeLists.txt
+++ b/Tests/FindCups/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(Cups REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_CUPS_VERSION="${CUPS_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_CUPS_VERSION="${Cups_VERSION}")
 
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt Cups::Cups)
diff --git a/Tests/FindCups/Test/main.c b/Tests/FindCups/Test/main.c
index 86952db..cca845a 100644
--- a/Tests/FindCups/Test/main.c
+++ b/Tests/FindCups/Test/main.c
@@ -1,4 +1,6 @@
 #include <cups/cups.h>
+#include <stdio.h>
+#include <string.h>
 
 int main(void)
 {
@@ -8,5 +10,12 @@
   num_options = cupsAddOption(CUPS_COPIES, "1", num_options, &options);
   cupsFreeOptions(num_options, options);
 
-  return 0;
+  char version_str[16];
+  snprintf(version_str, 16, "%d.%d.%d", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR,
+           CUPS_VERSION_PATCH);
+
+  printf("Found CUPS version %s, expected version %s\n", version_str,
+         CMAKE_EXPECTED_CUPS_VERSION);
+
+  return strcmp(version_str, CMAKE_EXPECTED_CUPS_VERSION);
 }
diff --git a/Tests/FindDevIL/Test/CMakeLists.txt b/Tests/FindDevIL/Test/CMakeLists.txt
index 2b72cf8..f82b7fe 100644
--- a/Tests/FindDevIL/Test/CMakeLists.txt
+++ b/Tests/FindDevIL/Test/CMakeLists.txt
@@ -4,19 +4,21 @@
 
 find_package(DevIL)
 
-#FIXME: check version too.
-# add_definitions(
-#  -DCMAKE_EXPECTED_SDL_VERSION_MAJOR=${SDL_VERSION_MAJOR}
-#  -DCMAKE_EXPECTED_SDL_VERSION_MINOR=${SDL_VERSION_MINOR}
-#  -DCMAKE_EXPECTED_SDL_VERSION_PATCH=${SDL_VERSION_PATCH})
-
 add_executable(test_devil_var main.c)
 target_include_directories(test_devil_var PRIVATE ${IL_INCLUDE_DIRS})
 target_link_libraries(test_devil_var PRIVATE ${IL_LIBRARIES})
+target_compile_definitions(
+  test_devil_var
+  PRIVATE CMAKE_EXPECTED_DEVIL_VERSION="${DevIL_VERSION}"
+)
 add_test(NAME test_devil_var COMMAND test_devil_var)
 
 add_executable(test_devil_il_tgt main.c)
 target_link_libraries(test_devil_il_tgt DevIL::IL)
+target_compile_definitions(
+  test_devil_il_tgt
+  PRIVATE CMAKE_EXPECTED_DEVIL_VERSION="${DevIL_VERSION}"
+)
 add_test(NAME test_devil_il_tgt COMMAND test_devil_il_tgt)
 
 add_executable(test_devil_ilu_tgt main_ilu.c)
diff --git a/Tests/FindDevIL/Test/main.c b/Tests/FindDevIL/Test/main.c
index dfb2f63..f7b2c8b 100644
--- a/Tests/FindDevIL/Test/main.c
+++ b/Tests/FindDevIL/Test/main.c
@@ -1,4 +1,6 @@
 #include <IL/il.h>
+#include <stdio.h>
+#include <string.h>
 
 int main(void)
 {
@@ -6,5 +8,16 @@
   ilInit();
 
   ilShutDown();
-  return 0;
+
+  int version = IL_VERSION;
+  int major = version / 100;
+  int minor = version / 10 % 10;
+  int patch = version % 10;
+  char version_string[100];
+  snprintf(version_string, sizeof(version_string), "%d.%d.%d", major, minor,
+           patch);
+
+  printf("Found DevIL version %s, expected version %s\n", version_string,
+         CMAKE_EXPECTED_DEVIL_VERSION);
+  return strcmp(version_string, CMAKE_EXPECTED_DEVIL_VERSION);
 }
diff --git a/Tests/FindEXPAT/Test/CMakeLists.txt b/Tests/FindEXPAT/Test/CMakeLists.txt
index a77545d..a75d5c4 100644
--- a/Tests/FindEXPAT/Test/CMakeLists.txt
+++ b/Tests/FindEXPAT/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(EXPAT REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_EXPAT_VERSION="${EXPAT_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_EXPAT_VERSION="${EXPAT_VERSION}")
 
 add_executable(testexpat_tgt main.c)
 target_link_libraries(testexpat_tgt EXPAT::EXPAT)
diff --git a/Tests/FindFreetype/Test/CMakeLists.txt b/Tests/FindFreetype/Test/CMakeLists.txt
index 857777e..fe2b754 100644
--- a/Tests/FindFreetype/Test/CMakeLists.txt
+++ b/Tests/FindFreetype/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(Freetype REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_FREETYPE_VERSION="${FREETYPE_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_FREETYPE_VERSION="${Freetype_VERSION}")
 
 add_executable(testfreetype_tgt main.c)
 target_link_libraries(testfreetype_tgt Freetype::Freetype)
diff --git a/Tests/FindGnuTLS/Test/CMakeLists.txt b/Tests/FindGnuTLS/Test/CMakeLists.txt
index 2a01298..b0e19e3 100644
--- a/Tests/FindGnuTLS/Test/CMakeLists.txt
+++ b/Tests/FindGnuTLS/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(GnuTLS REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_GNUTLS_VERSION="${GNUTLS_VERSION}")
+add_definitions(-DCMAKE_EXPECTED_GNUTLS_VERSION="${GnuTLS_VERSION}")
 
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt GnuTLS::GnuTLS)
diff --git a/Tests/FindJasper/Test/CMakeLists.txt b/Tests/FindJasper/Test/CMakeLists.txt
index 93873bf..70b1719 100644
--- a/Tests/FindJasper/Test/CMakeLists.txt
+++ b/Tests/FindJasper/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(Jasper)
 
-add_definitions(-DCMAKE_EXPECTED_JASPER_VERSION="${JASPER_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_JASPER_VERSION="${Jasper_VERSION}")
 
 add_executable(test_jasper_tgt main.c)
 target_link_libraries(test_jasper_tgt Jasper::Jasper)
diff --git a/Tests/FindLTTngUST/Test/CMakeLists.txt b/Tests/FindLTTngUST/Test/CMakeLists.txt
index c9084d7..355c74c 100644
--- a/Tests/FindLTTngUST/Test/CMakeLists.txt
+++ b/Tests/FindLTTngUST/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(LTTngUST REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_LTTNGUST_VERSION="${LTTNGUST_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_LTTNGUST_VERSION="${LTTngUST_VERSION}")
 add_definitions(-DCMAKE_LTTNGUST_HAS_TRACEF="${LTTNGUST_HAS_TRACEF}")
 add_definitions(-DCMAKE_LTTNGUST_HAS_TRACELOG="${LTTNGUST_HAS_TRACELOG}")
 
diff --git a/Tests/FindLibLZMA/Test/CMakeLists.txt b/Tests/FindLibLZMA/Test/CMakeLists.txt
index ae8d340..d5b8d4d 100644
--- a/Tests/FindLibLZMA/Test/CMakeLists.txt
+++ b/Tests/FindLibLZMA/Test/CMakeLists.txt
@@ -4,6 +4,8 @@
 
 find_package(LibLZMA REQUIRED)
 
+add_definitions(-DCMAKE_EXPECTED_LIBLZMA_VERSION="${LibLZMA_VERSION}")
+
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt LibLZMA::LibLZMA)
 add_test(NAME test_tgt COMMAND test_tgt)
diff --git a/Tests/FindLibLZMA/Test/main.c b/Tests/FindLibLZMA/Test/main.c
index 3da5a37..818cf86 100644
--- a/Tests/FindLibLZMA/Test/main.c
+++ b/Tests/FindLibLZMA/Test/main.c
@@ -1,5 +1,6 @@
 #include <assert.h>
 #include <lzma.h>
+#include <stdio.h>
 #include <string.h>
 
 static uint8_t const test_string[9] = "123456789";
@@ -11,5 +12,8 @@
   uint32_t crc = lzma_crc32(test_string, sizeof(test_string), 0);
   assert(crc == test_vector);
 
-  return 0;
+  printf("Found LibLZMA version %s, expected version %s\n",
+         lzma_version_string(), CMAKE_EXPECTED_LIBLZMA_VERSION);
+
+  return strcmp(lzma_version_string(), CMAKE_EXPECTED_LIBLZMA_VERSION);
 }
diff --git a/Tests/FindLibXml2/Test/CMakeLists.txt b/Tests/FindLibXml2/Test/CMakeLists.txt
index 3551daf..4adbd3b 100644
--- a/Tests/FindLibXml2/Test/CMakeLists.txt
+++ b/Tests/FindLibXml2/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(LibXml2 REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_LibXml2_VERSION="${LIBXML2_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_LibXml2_VERSION="${LibXml2_VERSION}")
 
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt LibXml2::LibXml2)
diff --git a/Tests/FindLibXslt/Test/CMakeLists.txt b/Tests/FindLibXslt/Test/CMakeLists.txt
index 0f23500..8059012 100644
--- a/Tests/FindLibXslt/Test/CMakeLists.txt
+++ b/Tests/FindLibXslt/Test/CMakeLists.txt
@@ -6,7 +6,7 @@
 find_package(LibXml2 REQUIRED)
 find_package(LibXslt REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_LibXslt_VERSION="${LIBXSLT_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_LibXslt_VERSION="${LibXslt_VERSION}")
 
 add_executable(libxslt_tgt libxslt.c)
 if(Iconv_FOUND)
diff --git a/Tests/FindPNG/Test/CMakeLists.txt b/Tests/FindPNG/Test/CMakeLists.txt
index 6cc9ca2..5ac2b39 100644
--- a/Tests/FindPNG/Test/CMakeLists.txt
+++ b/Tests/FindPNG/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(PNG REQUIRED)
 
-add_definitions(-DCMAKE_EXPECTED_PNG_VERSION="${PNG_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_PNG_VERSION="${PNG_VERSION}")
 
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt PNG::PNG)
diff --git a/Tests/FindPackageCMakeTest/CMakeLists.txt b/Tests/FindPackageCMakeTest/CMakeLists.txt
index bd1887a..37a63eb 100644
--- a/Tests/FindPackageCMakeTest/CMakeLists.txt
+++ b/Tests/FindPackageCMakeTest/CMakeLists.txt
@@ -117,7 +117,7 @@
 endforeach()
 
 # Enable framework and bundle searching.  Make sure bundles are found
-# before unix-syle packages.
+# before unix-style packages.
 set(CMAKE_FIND_FRAMEWORK LAST)
 set(CMAKE_FIND_APPBUNDLE FIRST)
 
@@ -584,6 +584,17 @@
 unset(SortLib_VERSION)
 
 
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+# Expected to default to 'NATURAL' and 'DEC'
+unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
+unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
+FIND_PACKAGE(SortLib CONFIG)
+IF (NOT "${SortLib_VERSION}" STREQUAL "3.10.1")
+  message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Default! ${SortLib_VERSION}")
+endif()
+unset(SortLib_VERSION)
+
+
 set(SortFramework_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 SET(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
 SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
diff --git a/Tests/FindPackageCpsTest/CMakeLists.txt b/Tests/FindPackageCpsTest/CMakeLists.txt
index 574f5a7..43caab4 100644
--- a/Tests/FindPackageCpsTest/CMakeLists.txt
+++ b/Tests/FindPackageCpsTest/CMakeLists.txt
@@ -90,6 +90,7 @@
   unset(SortLib_VERSION)
 endforeach()
 
+
 set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
 set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
@@ -100,6 +101,7 @@
 set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 unset(SortLib_VERSION)
 
+
 set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 FIND_PACKAGE(SortLib 4.0 CONFIG)
 IF (NOT "${SortLib_VERSION}" STREQUAL "4.0.0")
@@ -107,6 +109,18 @@
 endif()
 unset(SortLib_VERSION)
 
+
+set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
+# Expected to default to 'NATURAL' and 'DEC'
+unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
+unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
+FIND_PACKAGE(SortLib CONFIG)
+IF (NOT "${SortLib_VERSION}" STREQUAL "3.10.1")
+  message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Default! ${SortLib_VERSION}")
+endif()
+unset(SortLib_VERSION)
+
+
 set(SortFramework_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
 set(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
@@ -117,6 +131,7 @@
 set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 unset(SortFramework_VERSION)
 
+
 set(SortFramework_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
 set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
@@ -127,6 +142,7 @@
 set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE)
 unset(SortFramework_VERSION)
 
+
 unset(CMAKE_FIND_PACKAGE_SORT_ORDER)
 unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION)
 
diff --git a/Tests/FindPostgreSQL/Test/CMakeLists.txt b/Tests/FindPostgreSQL/Test/CMakeLists.txt
index 1bc5c56..1e1d215 100644
--- a/Tests/FindPostgreSQL/Test/CMakeLists.txt
+++ b/Tests/FindPostgreSQL/Test/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 find_package(PostgreSQL REQUIRED COMPONENTS Server)
 
-add_definitions(-DCMAKE_EXPECTED_POSTGRESQL_VERSION="${PostgreSQL_VERSION_STRING}")
+add_definitions(-DCMAKE_EXPECTED_POSTGRESQL_VERSION="${PostgreSQL_VERSION}")
 
 add_executable(test_tgt main.c)
 target_link_libraries(test_tgt PostgreSQL::PostgreSQL)
diff --git a/Tests/FindTIFF/Test/CMakeLists.txt b/Tests/FindTIFF/Test/CMakeLists.txt
index c734b25..0ca6ac3 100644
--- a/Tests/FindTIFF/Test/CMakeLists.txt
+++ b/Tests/FindTIFF/Test/CMakeLists.txt
@@ -6,6 +6,10 @@
 
 add_executable(test_tiff_tgt main.c)
 target_link_libraries(test_tiff_tgt TIFF::TIFF)
+target_compile_definitions(
+  test_tiff_tgt
+  PRIVATE CMAKE_EXPECTED_TIFF_VERSION="${TIFF_VERSION}"
+)
 add_test(NAME test_tiff_tgt COMMAND test_tiff_tgt)
 
 add_executable(test_tiffxx_tgt main.cxx)
@@ -15,6 +19,10 @@
 add_executable(test_tiff_var main.c)
 target_include_directories(test_tiff_var PRIVATE ${TIFF_INCLUDE_DIRS})
 target_link_libraries(test_tiff_var PRIVATE ${TIFF_LIBRARIES})
+target_compile_definitions(
+  test_tiff_var
+  PRIVATE CMAKE_EXPECTED_TIFF_VERSION="${TIFF_VERSION}"
+)
 add_test(NAME test_tiff_var COMMAND test_tiff_var)
 
 add_executable(test_tiffxx_var main.cxx)
diff --git a/Tests/FindTIFF/Test/main.c b/Tests/FindTIFF/Test/main.c
index bce4a3e..5230eac 100644
--- a/Tests/FindTIFF/Test/main.c
+++ b/Tests/FindTIFF/Test/main.c
@@ -1,4 +1,6 @@
 #include <assert.h>
+#include <stdio.h>
+#include <string.h>
 #include <tiffio.h>
 
 int main(void)
@@ -8,5 +10,26 @@
   TIFF* tiff = TIFFOpen("invalid.tiff", "r");
   assert(!tiff);
 
-  return 0;
+  char const* info = TIFFGetVersion();
+  char const* version_prefix = "Version ";
+  char const* start = strstr(info, version_prefix);
+  char version_str[16];
+
+  if (start) {
+    start += strlen(version_prefix);
+    int major, minor, patch;
+
+    if (sscanf(start, "%d.%d.%d", &major, &minor, &patch) == 3) {
+      snprintf(version_str, sizeof(version_str), "%d.%d.%d", major, minor,
+               patch);
+      printf("Found TIFF version %s, expected version %s\n", version_str,
+             CMAKE_EXPECTED_TIFF_VERSION);
+
+      return strcmp(version_str, CMAKE_EXPECTED_TIFF_VERSION);
+    }
+  }
+
+  fprintf(stderr,
+          "TIFF version not found or TIFF version could not be parsed\n");
+  return 1;
 }
diff --git a/Tests/FortranOnly/CMakeLists.txt b/Tests/FortranOnly/CMakeLists.txt
index d32c3bd..8643318 100644
--- a/Tests/FortranOnly/CMakeLists.txt
+++ b/Tests/FortranOnly/CMakeLists.txt
@@ -3,6 +3,8 @@
 project(FortranOnly Fortran)
 message("CTEST_FULL_OUTPUT ")
 
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 if("${CMAKE_Fortran_COMPILER_ID};${CMAKE_Fortran_SIMULATE_ID}" MATCHES "^Intel(LLVM)?;MSVC$")
   string(APPEND CMAKE_Fortran_FLAGS_DEBUG " -Z7")
   string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO " -Z7")
diff --git a/Tests/MakeClean/ToClean/CMakeLists.txt b/Tests/MakeClean/ToClean/CMakeLists.txt
index a05c38b..3f43121 100644
--- a/Tests/MakeClean/ToClean/CMakeLists.txt
+++ b/Tests/MakeClean/ToClean/CMakeLists.txt
@@ -1,6 +1,8 @@
 cmake_minimum_required(VERSION 3.14)
 project(ToClean)
 
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Utility variables
 set(CSD ${CMAKE_CURRENT_SOURCE_DIR})
 set(CBD ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/Tests/PDBDirectoryAndName/CMakeLists.txt b/Tests/PDBDirectoryAndName/CMakeLists.txt
index de287d8..e9494db 100644
--- a/Tests/PDBDirectoryAndName/CMakeLists.txt
+++ b/Tests/PDBDirectoryAndName/CMakeLists.txt
@@ -76,16 +76,27 @@
 
 set(pdbs "")
 foreach(t ${my_targets})
+  set(with_compile 0)
   get_property(pdb_name TARGET ${t} PROPERTY PDB_NAME)
   get_property(pdb_dir TARGET ${t} PROPERTY PDB_OUTPUT_DIRECTORY)
   if(NOT pdb_name)
+    set(with_compile 1)
     get_property(pdb_name TARGET ${t} PROPERTY COMPILE_PDB_NAME)
   endif()
   if(NOT pdb_dir)
     get_property(pdb_dir TARGET ${t} PROPERTY COMPILE_PDB_OUTPUT_DIRECTORY)
   endif()
   if(NOT pdb_dir)
-    set(pdb_dir ${CMAKE_CURRENT_BINARY_DIR})
+    if (NOT with_compile)
+      set(pdb_dir ${CMAKE_CURRENT_BINARY_DIR})
+    elseif (CMAKE_GENERATOR MATCHES "Ninja" OR
+            CMAKE_GENERATOR MATCHES "Makefiles")
+      set(pdb_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${t}.dir)
+    elseif (CMAKE_GENERATOR MATCHES "Visual Studio")
+      set(pdb_dir ${CMAKE_CURRENT_BINARY_DIR}/${t}.dir)
+    else ()
+      set(pdb_dir ${CMAKE_CURRENT_BINARY_DIR}/${t}.dir)
+    endif ()
   endif()
   if (pdb_dir MATCHES "\\$<.*>")
     # Skip per-configuration subdirectory if the value contained
diff --git a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
index 5c70e43..6c23c95 100644
--- a/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
+++ b/Tests/QtAutogen/GlobalAutogenTarget/CMakeLists.txt
@@ -76,6 +76,7 @@
         "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}"
         "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
         "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}"
+        -DCMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY:STRING=FULL
     WORKING_DIRECTORY "${GAT_BDIR}"
     OUTPUT_VARIABLE output
     RESULT_VARIABLE result)
diff --git a/Tests/RunCMake/AutoExportDll/AutoExport.cmake b/Tests/RunCMake/AutoExportDll/AutoExport.cmake
index 024c647..8abf7fd 100644
--- a/Tests/RunCMake/AutoExportDll/AutoExport.cmake
+++ b/Tests/RunCMake/AutoExportDll/AutoExport.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(autoexport)
 set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${autoexport_BINARY_DIR}/bin)
diff --git a/Tests/RunCMake/AutoExportDll/AutoExportShort.cmake b/Tests/RunCMake/AutoExportDll/AutoExportShort.cmake
new file mode 100644
index 0000000..08ee5d4
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AutoExportShort.cmake
@@ -0,0 +1,29 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+project(autoexport)
+set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${autoexport_BINARY_DIR}/bin)
+add_subdirectory(sub)
+add_library(objlib OBJECT objlib.c)
+set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)
+add_library(autoexport SHARED hello.cxx world.cxx foo.c $<TARGET_OBJECTS:objlib>)
+add_library(autoexport3 SHARED cppCLI.cxx)
+if(MSVC AND NOT MSVC_VERSION VERSION_LESS 1600
+   AND NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64")
+  set_property(TARGET autoexport3 PROPERTY COMMON_LANGUAGE_RUNTIME "")
+endif()
+
+add_executable(say say.cxx)
+if(MSVC)
+  set_target_properties(say PROPERTIES ENABLE_EXPORTS ON)
+  add_library(autoexport_for_exec SHARED hello2.c)
+  target_link_libraries(autoexport_for_exec say)
+  if(NOT MSVC_VERSION VERSION_LESS 1600 AND
+     NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64")
+    enable_language(ASM_MASM)
+    target_sources(autoexport PRIVATE nop.asm)
+    set_property(SOURCE nop.asm PROPERTY COMPILE_FLAGS /safeseh)
+    target_compile_definitions(say PRIVATE HAS_JUSTNOP)
+  endif()
+endif()
+target_link_libraries(say autoexport autoexport2 autoexport3)
diff --git a/Tests/RunCMake/AutoExportDll/AutoExportShortBuild-stderr.txt b/Tests/RunCMake/AutoExportDll/AutoExportShortBuild-stderr.txt
new file mode 100644
index 0000000..d483c2c
--- /dev/null
+++ b/Tests/RunCMake/AutoExportDll/AutoExportShortBuild-stderr.txt
@@ -0,0 +1 @@
+^.*$
diff --git a/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake b/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake
index 9f65219..a2acf8b 100644
--- a/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake
+++ b/Tests/RunCMake/AutoExportDll/RunCMakeTest.cmake
@@ -1,66 +1,73 @@
 include(RunCMake)
 set(RunCMake_TEST_NO_CLEAN TRUE)
-set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AutoExport-build")
-# start by cleaning up because we don't clean up along the way
-file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
-# configure the AutoExport test
-run_cmake(AutoExport)
-unset(RunCMake_TEST_OPTIONS)
-# don't run this test on Watcom or Borland make as it is not supported
-if(RunCMake_GENERATOR MATCHES "Watcom WMake|Borland Makefiles")
-  return()
-endif()
-if(CMAKE_CXX_COMPILER_ID STREQUAL "OrangeC")
-  return()
-endif()
-if(RunCMake_GENERATOR MATCHES "Ninja|Visual Studio" AND
-   CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
-  set(EXPORTS TRUE)
-endif()
-# we build debug so the say.exe will be found in Debug/say.exe for
-# Visual Studio generators
-if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  set(INTDIR "Debug/")
-endif()
-# build AutoExport
-run_cmake_command(AutoExportBuild ${CMAKE_COMMAND} --build
-  ${RunCMake_TEST_BINARY_DIR} --config Debug --clean-first)
-# save the current timestamp of exports.def
-if(EXPORTS)
-  set(EXPORTS_DEF "${RunCMake_TEST_BINARY_DIR}/say.dir/${INTDIR}exports.def")
-  if(NOT EXISTS "${EXPORTS_DEF}")
-    set(EXPORTS_DEF
-      "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/say.dir/${INTDIR}exports.def")
+
+function (run_cmake_AutoExport name dir)
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${name}-build")
+  # start by cleaning up because we don't clean up along the way
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  # configure the AutoExport test
+  run_cmake(${name})
+  unset(RunCMake_TEST_OPTIONS)
+  # don't run this test on Watcom or Borland make as it is not supported
+  if(RunCMake_GENERATOR MATCHES "Watcom WMake|Borland Makefiles")
+    return()
   endif()
-  file(TIMESTAMP "${EXPORTS_DEF}" timestamp)
-  if(NOT timestamp)
-    message(SEND_ERROR "Could not get timestamp for \"${EXPORTS_DEF}\"")
+  if(CMAKE_CXX_COMPILER_ID STREQUAL "OrangeC")
+    return()
   endif()
-endif()
-# run the executable that uses symbols from the dll
-if(WIN32)
-  set(EXE_EXT ".exe")
-endif()
-run_cmake_command(AutoExportRun
-  ${RunCMake_TEST_BINARY_DIR}/bin/${INTDIR}say${EXE_EXT})
-# build AutoExport again without modification
-run_cmake_command(AutoExportBuildAgain ${CMAKE_COMMAND} --build
-  ${RunCMake_TEST_BINARY_DIR} --config Debug)
-# compare timestamps of exports.def to make sure it has not been updated
-if(EXPORTS)
-  file(TIMESTAMP "${EXPORTS_DEF}" timestamp_after)
-  if(NOT timestamp_after)
-    message(SEND_ERROR "Could not get timestamp for \"${EXPORTS_DEF}\"")
+  if(RunCMake_GENERATOR MATCHES "Ninja|Visual Studio" AND
+     CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+    set(EXPORTS TRUE)
   endif()
-  if (timestamp_after STREQUAL timestamp)
-    message(STATUS "AutoExportTimeStamp - PASSED")
-  else()
-    message(SEND_ERROR "\"${EXPORTS_DEF}\" has been updated.")
+  # we build debug so the say.exe will be found in Debug/say.exe for
+  # Visual Studio generators
+  if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(INTDIR "Debug/")
   endif()
-endif()
+  # build AutoExport
+  run_cmake_command(${name}Build ${CMAKE_COMMAND} --build
+    ${RunCMake_TEST_BINARY_DIR} --config Debug --clean-first)
+  # save the current timestamp of exports.def
+  if(EXPORTS)
+    set(EXPORTS_DEF "${RunCMake_TEST_BINARY_DIR}/${dir}/${INTDIR}exports.def")
+    if(NOT EXISTS "${EXPORTS_DEF}")
+      set(EXPORTS_DEF
+        "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/${dir}/${INTDIR}exports.def")
+    endif()
+    file(TIMESTAMP "${EXPORTS_DEF}" timestamp)
+    if(NOT timestamp)
+      message(SEND_ERROR "Could not get timestamp for \"${EXPORTS_DEF}\"")
+    endif()
+  endif()
+  # run the executable that uses symbols from the dll
+  if(WIN32)
+    set(EXE_EXT ".exe")
+  endif()
+  run_cmake_command(${name}Run
+    ${RunCMake_TEST_BINARY_DIR}/bin/${INTDIR}say${EXE_EXT})
+  # build AutoExport again without modification
+  run_cmake_command(${name}BuildAgain ${CMAKE_COMMAND} --build
+    ${RunCMake_TEST_BINARY_DIR} --config Debug)
+  # compare timestamps of exports.def to make sure it has not been updated
+  if(EXPORTS)
+    file(TIMESTAMP "${EXPORTS_DEF}" timestamp_after)
+    if(NOT timestamp_after)
+      message(SEND_ERROR "Could not get timestamp for \"${EXPORTS_DEF}\"")
+    endif()
+    if (timestamp_after STREQUAL timestamp)
+      message(STATUS "AutoExportTimeStamp - PASSED")
+    else()
+      message(SEND_ERROR "\"${EXPORTS_DEF}\" has been updated.")
+    endif()
+  endif()
+endfunction ()
+run_cmake_AutoExport(AutoExport "say.dir")
+if (CMAKE_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+  run_cmake_AutoExport(AutoExportShort ".o/0cb3d702")
+endif ()
 
 function(run_AIXExportExplicit)
-  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AIXExpotExplicit-build")
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AIXExportExplicit-build")
   run_cmake(AIXExportExplicit)
   set(RunCMake_TEST_NO_CLEAN 1)
   set(RunCMake_TEST_OUTPUT_MERGE TRUE)
diff --git a/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeCommon.cmake b/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeCommon.cmake
index e0f3ce8..f3cc181 100644
--- a/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeCommon.cmake
+++ b/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeCommon.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 
 find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core Widgets Gui)
diff --git a/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortCommon.cmake b/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortCommon.cmake
new file mode 100644
index 0000000..ebe308d
--- /dev/null
+++ b/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortCommon.cmake
@@ -0,0 +1,10 @@
+set(CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(CXX)
+
+find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core Widgets Gui)
+
+add_library(dummy SHARED empty.cpp)
+target_link_libraries(dummy Qt${with_qt_version}::Core
+                            Qt${with_qt_version}::Widgets
+                            Qt${with_qt_version}::Gui)
diff --git a/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortOff.cmake b/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortOff.cmake
new file mode 100644
index 0000000..f1293c6
--- /dev/null
+++ b/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortOff.cmake
@@ -0,0 +1,3 @@
+include("${CMAKE_CURRENT_LIST_DIR}/AutogenUseSystemIncludeShortCommon.cmake")
+
+set_target_properties(dummy PROPERTIES AUTOGEN_USE_SYSTEM_INCLUDE OFF)
diff --git a/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortOn.cmake b/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortOn.cmake
new file mode 100644
index 0000000..802bb28
--- /dev/null
+++ b/Tests/RunCMake/Autogen_1/AutogenUseSystemIncludeShortOn.cmake
@@ -0,0 +1,3 @@
+include("${CMAKE_CURRENT_LIST_DIR}/AutogenUseSystemIncludeShortCommon.cmake")
+
+set_target_properties(dummy PROPERTIES AUTOGEN_USE_SYSTEM_INCLUDE ON)
diff --git a/Tests/RunCMake/Autogen_1/CMP0151-common.cmake b/Tests/RunCMake/Autogen_1/CMP0151-common.cmake
index bbefd5f..41c3325 100644
--- a/Tests/RunCMake/Autogen_1/CMP0151-common.cmake
+++ b/Tests/RunCMake/Autogen_1/CMP0151-common.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 
 find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core Widgets Gui)
diff --git a/Tests/RunCMake/Autogen_1/CMP0151Short-common.cmake b/Tests/RunCMake/Autogen_1/CMP0151Short-common.cmake
new file mode 100644
index 0000000..cd0cd38
--- /dev/null
+++ b/Tests/RunCMake/Autogen_1/CMP0151Short-common.cmake
@@ -0,0 +1,12 @@
+set(CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(CXX)
+
+find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core Widgets Gui)
+
+set(CMAKE_AUTOMOC ON)
+
+add_library(dummy SHARED empty.cpp)
+target_link_libraries(dummy Qt${with_qt_version}::Core
+                            Qt${with_qt_version}::Widgets
+                            Qt${with_qt_version}::Gui)
diff --git a/Tests/RunCMake/Autogen_1/CMP0151Short-new.cmake b/Tests/RunCMake/Autogen_1/CMP0151Short-new.cmake
new file mode 100644
index 0000000..439238e
--- /dev/null
+++ b/Tests/RunCMake/Autogen_1/CMP0151Short-new.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/CMP0151Short-common.cmake")
diff --git a/Tests/RunCMake/Autogen_1/CMP0151Short-old.cmake b/Tests/RunCMake/Autogen_1/CMP0151Short-old.cmake
new file mode 100644
index 0000000..439238e
--- /dev/null
+++ b/Tests/RunCMake/Autogen_1/CMP0151Short-old.cmake
@@ -0,0 +1 @@
+include("${CMAKE_CURRENT_LIST_DIR}/CMP0151Short-common.cmake")
diff --git a/Tests/RunCMake/Autogen_1/MocPredefs.cmake b/Tests/RunCMake/Autogen_1/MocPredefs.cmake
index 8307e04..6ea192a 100644
--- a/Tests/RunCMake/Autogen_1/MocPredefs.cmake
+++ b/Tests/RunCMake/Autogen_1/MocPredefs.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 
 find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core)
diff --git a/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake b/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake
index c49f09c..ab68797 100644
--- a/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake
@@ -38,13 +38,17 @@
           set(test_expect_stdout_common "-*${CMAKE_INCLUDE_SYSTEM_FLAG_CXX}")
         endif()
         set(test_expect_stdout_1 "${test_expect_stdout_common}")
+        set(test_expect_stdout_1_short "${test_expect_stdout_common}")
         set(test_expect_stdout_2 "${test_expect_stdout_common}")
         string(APPEND test_expect_stdout_1 " *(\"[^\"]*|([^ ]|\\ )*)[\\/]dummy_autogen[\\/]include")
+        string(APPEND test_expect_stdout_1_short " *(\"[^\"]*|([^ ]|\\ )*)[\\/]\\.o[\\/]9624d702[\\/]autogen[\\/]include")
         if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
           string(APPEND test_expect_stdout_1 "_Debug")
+          string(APPEND test_expect_stdout_1_short "_Debug")
         endif()
         string(APPEND test_expect_stdout_2 " *(\"[^\"]*|([^ ]|\\ )*)[\\/]QtCore")
         set(test_expect_stdout "${test_expect_stdout_1}.*${test_expect_stdout_2}")
+        set(test_expect_stdout_short "${test_expect_stdout_1_short}.*${test_expect_stdout_2}")
 
         block()
           set(RunCMake_TEST_BINARY_DIR  ${RunCMake_BINARY_DIR}/CMP0151-new-build)
@@ -61,6 +65,24 @@
           set(RunCMake_TEST_EXPECT_stdout "${test_expect_stdout}")
           run_cmake_command(AutogenUseSystemIncludeOn-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
         endblock()
+
+        if (CMAKE_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+          block()
+            set(RunCMake_TEST_BINARY_DIR  ${RunCMake_BINARY_DIR}/CMP0151Short-new-build)
+            run_cmake_with_options(CMP0151Short-new ${RunCMake_TEST_OPTIONS}  -DCMAKE_AUTO${autogen_type}=ON -DCMAKE_POLICY_DEFAULT_CMP0151=NEW)
+            set(RunCMake_TEST_NO_CLEAN 1)
+            set(RunCMake_TEST_EXPECT_stdout "${test_expect_stdout_short}")
+            run_cmake_command(CMP0151Short-new-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
+          endblock()
+
+          block()
+            set(RunCMake_TEST_BINARY_DIR  ${RunCMake_BINARY_DIR}/AutogenUseSystemIncludeShortOn-build)
+            run_cmake_with_options(AutogenUseSystemIncludeShortOn ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTO${autogen_type}=ON -DCMAKE_POLICY_DEFAULT_CMP0151=NEW)
+            set(RunCMake_TEST_NO_CLEAN 1)
+            set(RunCMake_TEST_EXPECT_stdout "${test_expect_stdout_short}")
+            run_cmake_command(AutogenUseSystemIncludeShortOn-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
+          endblock()
+        endif ()
       endif()
 
       if(CMAKE_INCLUDE_FLAG_CXX)
@@ -68,10 +90,13 @@
           string(REGEX REPLACE "^-" "/" test_expect_stdout "${CMAKE_INCLUDE_FLAG_CXX}")
         else()
           set(test_expect_stdout "-*${CMAKE_INCLUDE_FLAG_CXX}")
+          set(test_expect_stdout_short "-*${CMAKE_INCLUDE_FLAG_CXX}")
         endif()
         string(APPEND test_expect_stdout " *(\"[^\"]*|([^ ]|\\ )*)[\\/]dummy_autogen[\\/]include")
+        string(APPEND test_expect_stdout_short " *(\"[^\"]*|([^ ]|\\ )*)[\\/]\\.o[\\/]9624d702[\\/]autogen[\\/]include")
         if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
           string(APPEND test_expect_stdout "_Debug")
+          string(APPEND test_expect_stdout_short "_Debug")
         endif()
 
         block()
@@ -89,6 +114,24 @@
           set(RunCMake_TEST_EXPECT_stdout "${test_expect_stdout}")
           run_cmake_command(AutogenUseSystemIncludeOff-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
         endblock()
+
+        if (CMAKE_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+          block()
+            set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0151Short-old-build)
+            run_cmake_with_options(CMP0151Short-old ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTO${autogen_type}=ON -DCMAKE_POLICY_DEFAULT_CMP0151=OLD)
+            set(RunCMake_TEST_NO_CLEAN 1)
+            set(RunCMake_TEST_EXPECT_stdout "${test_expect_stdout_short}")
+            run_cmake_command(CMP0151Short-old-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
+          endblock()
+
+          block()
+            set(RunCMake_TEST_BINARY_DIR  ${RunCMake_BINARY_DIR}/AutogenUseSystemIncludeShortOff-build)
+            run_cmake_with_options(AutogenUseSystemIncludeShortOff ${RunCMake_TEST_OPTIONS} -DCMAKE_AUTO${autogen_type}=ON -DCMAKE_POLICY_DEFAULT_CMP0151=NEW)
+            set(RunCMake_TEST_NO_CLEAN 1)
+            set(RunCMake_TEST_EXPECT_stdout "${test_expect_stdout_short}")
+            run_cmake_command(AutogenUseSystemIncludeShortOff-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
+          endblock()
+        endif()
       endif()
     endblock()
   endforeach()
diff --git a/Tests/RunCMake/Autogen_2/QtAutoMocDeps.cmake b/Tests/RunCMake/Autogen_2/QtAutoMocDeps.cmake
index fc3b2f2..c7ecb9d 100644
--- a/Tests/RunCMake/Autogen_2/QtAutoMocDeps.cmake
+++ b/Tests/RunCMake/Autogen_2/QtAutoMocDeps.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 
 find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core Widgets Gui)
diff --git a/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectories.cmake b/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectories.cmake
index 5cb0691..d1eb8b3 100644
--- a/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectories.cmake
+++ b/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectories.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 set(CMAKE_CXX_STANDARD 11)
 
diff --git a/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectoriesShort-check.cmake b/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectoriesShort-check.cmake
new file mode 100644
index 0000000..0b7ca57
--- /dev/null
+++ b/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectoriesShort-check.cmake
@@ -0,0 +1,46 @@
+# Read the JSON file into a variable
+set(autogenInfoFilePath "${RunCMake_TEST_BINARY_DIR}/.o/4bcad702/autogen_info/AutogenInfo.json")
+
+if(NOT IS_READABLE "${autogenInfoFilePath}")
+  set(RunCMake_TEST_FAILED "Expected autogen info file missing:\n \"${autogenInfoFilePath}\"")
+  return()
+endif()
+file(READ "${autogenInfoFilePath}" jsonRaw)
+
+# If multi-config generator, we are looking for MOC_INCLUDES_<CONFIG>.
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(mocKey "MOC_INCLUDES_Debug") # Pick one arbitrarily (they will all be the same in this test)
+# If single-config generator, we are looking for MOC_INCLUDES.
+else()
+  set(mocKey "MOC_INCLUDES")
+endif()
+
+string(JSON actualValue GET "${jsonRaw}" "${mocKey}")
+
+# The format of the MOC_INCLUDES entries in AutogenInfo.json depends on how long the paths are.
+# For short entries:
+#	"MOC_INCLUDES" : [ "<SHORT_PATH>" ]
+# For long entries:
+# 	"MOC_INCLUDES_Debug" :
+#	[
+#		"<SOME_PARTICULARLY_LONG_PATH>"
+#	],
+
+# Also, paths given to AUTOMOC_INCLUDE_DIRECTORIES must be absolute paths.
+# The code uses SystemTools::FileIsFullPath() to verify this, and it accepts
+# a forward slash at the beginning for both Windows (network path) and UNIX platforms.
+# Therefore, for the simplicity of this test, use a dummy value "/pass".
+
+# Strip the JSON format around the string for a true before/after comparison.
+string(REPLACE "[ \"" "" actualValue ${actualValue})
+string(REPLACE "\" ]" "" actualValue ${actualValue})
+
+# Final pass/fail comparison.
+set(expectedValue "/pass")
+
+if (NOT actualValue STREQUAL expectedValue)
+  set(RunCMake_TEST_FAILED "AUTOMOC_INCLUDE_DIRECTORIES override property not honored.")
+  string(APPEND RunCMake_TEST_FAILURE_MESSAGE
+    "Expected MOC_INCLUDES in AutogenInfo.json to have ${expectedValue} but found ${actualValue}."
+  )
+endif()
diff --git a/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectoriesShort.cmake b/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectoriesShort.cmake
new file mode 100644
index 0000000..34e3e6d
--- /dev/null
+++ b/Tests/RunCMake/Autogen_7/AutoMocIncludeDirectoriesShort.cmake
@@ -0,0 +1,18 @@
+set(CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(CXX)
+set(CMAKE_CXX_STANDARD 11)
+
+find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core)
+
+# Create a test library with an arbitrary include directory to later override with the property
+add_library(foo STATIC ../Autogen_common/example.cpp)
+target_include_directories(foo PRIVATE ../Autogen_common/example.h)
+
+# Set AUTOMOC_INCLUDE_DIRECTORIES with a test value to verify it replaces the above include directory
+# in AutogenInfo.json's MOC_INCLUDES list.
+# See comments in the -check.cmake counterpart for more information about this test.
+set_target_properties(foo PROPERTIES
+  AUTOMOC ON
+  AUTOMOC_INCLUDE_DIRECTORIES "/pass"
+)
diff --git a/Tests/RunCMake/Autogen_7/RunCMakeTest.cmake b/Tests/RunCMake/Autogen_7/RunCMakeTest.cmake
index d835cda..904f4ed 100644
--- a/Tests/RunCMake/Autogen_7/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Autogen_7/RunCMakeTest.cmake
@@ -7,4 +7,7 @@
     "-DCMAKE_PREFIX_PATH:STRING=${CMAKE_PREFIX_PATH}"
   )
   run_cmake(AutoMocIncludeDirectories)
+  if (CMAKE_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+    run_cmake(AutoMocIncludeDirectoriesShort)
+  endif ()
 endif()
diff --git a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
index 331d21d..2429f3f 100644
--- a/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
+++ b/Tests/RunCMake/BuildDepends/CustomCommandDepfile.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 cmake_policy(SET CMP0116 NEW)
 enable_language(C)
 
diff --git a/Tests/RunCMake/CMP0150/CMakeLists.txt b/Tests/RunCMake/CMP0150/CMakeLists.txt
index 371dccc..29a2e04 100644
--- a/Tests/RunCMake/CMP0150/CMakeLists.txt
+++ b/Tests/RunCMake/CMP0150/CMakeLists.txt
@@ -20,6 +20,7 @@
   execGitCommand("${workDir}" config user.email "testauthor@cmake.org")
   execGitCommand("${workDir}" config user.name testauthor)
   execGitCommand("${workDir}" config core.autocrlf false)
+  execGitCommand("${workDir}" config commit.gpgsign false)
   execGitCommand("${workDir}" add CMakeLists.txt)
   execGitCommand("${workDir}" commit -m "Initial commit")
 endfunction()
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index e8fc9da..e6b60a6 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -420,7 +420,8 @@
   list(APPEND FileAPI_ARGS -DJsonCpp_VERSION_STRING=${JsonCpp_VERSION_STRING})
 endif()
 add_RunCMake_test(FileAPI -DPython_EXECUTABLE=${Python_EXECUTABLE}
-                          -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID})
+                          -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}
+                          -DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA})
 if(CMAKE_GENERATOR MATCHES "Make|Ninja")
   add_RunCMake_test(Instrumentation)
 endif()
@@ -521,7 +522,8 @@
 add_RunCMake_test(GenEx-PATH)
 add_RunCMake_test(GenEx-PATH_EQUAL)
 add_RunCMake_test(GenEx-LIST)
-add_RunCMake_test(GeneratorExpression)
+add_RunCMake_test(GeneratorExpression -DCMake_TEST_OBJC=${CMake_TEST_OBJC} -DCMake_TEST_Fortran=${CMake_TEST_Fortran}
+                                      -DCMake_TEST_CUDA=${CMake_TEST_CUDA} -DCMake_TEST_HIP=${CMake_TEST_HIP})
 add_RunCMake_test(GeneratorExpressionShortCircuit)
 add_RunCMake_test(GeneratorInstance)
 add_RunCMake_test(GeneratorPlatform)
@@ -616,7 +618,7 @@
 if(NOT CMAKE_GENERATOR MATCHES "Visual Studio")
   add_RunCMake_test(VisibilityPreset)
 endif()
-if (QT4_FOUND)
+if (Qt4_FOUND)
   set(CompatibleInterface_ARGS -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE})
 endif()
 add_RunCMake_test(CompatibleInterface)
@@ -792,6 +794,7 @@
 add_RunCMake_test(TargetPolicies)
 add_RunCMake_test(alias_targets)
 add_RunCMake_test(InterfaceLibrary)
+add_RunCMake_test(IntermediateDirStrategy)
 add_RunCMake_test(no_install_prefix)
 add_RunCMake_test(configure_file)
 if(CTestTestTimeout_TIME)
@@ -868,10 +871,10 @@
 if(CMake_TEST_Qt5)
   find_package(Qt5Core QUIET)
 endif()
-if (CMake_TEST_Qt4 AND CMake_TEST_Qt5 AND QT4_FOUND AND Qt5Core_FOUND AND NOT Qt5Core_VERSION VERSION_LESS 5.1.0)
+if (CMake_TEST_Qt4 AND CMake_TEST_Qt5 AND Qt4_FOUND AND Qt5Core_FOUND AND NOT Qt5Core_VERSION VERSION_LESS 5.1.0)
   add_RunCMake_test(IncompatibleQt)
 endif()
-if (CMake_TEST_Qt4 AND QT4_FOUND)
+if (CMake_TEST_Qt4 AND Qt4_FOUND)
   add_RunCMake_test(ObsoleteQtMacros -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE})
 endif()
 
@@ -939,7 +942,7 @@
   endif()
 endif()
 
-if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin|Windows)"
+if (CMAKE_SYSTEM_NAME MATCHES "(Linux|Darwin|Windows|OpenBSD|FreeBSD|NetBSD|MirBSD)"
     AND CMAKE_C_COMPILER_ID MATCHES "^(AppleClang|Clang|GNU|MSVC|NVIDIA)$"
     AND NOT CMAKE_GENERATOR STREQUAL "Green Hills MULTI")
   add_RunCMake_test(LinkerSelection -DCMake_TEST_CUDA=${CMake_TEST_CUDA}
@@ -1339,6 +1342,12 @@
   -DCMAKE_C_SIMULATE_ID=${CMAKE_C_SIMULATE_ID}
   -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION})
 
+# This test can take a long time due to the number of test cases.
+# Provide an option to customize it.
+if(DEFINED CMake_TEST_PrecompileHeaders_TIMEOUT)
+  set_property(TEST RunCMake.PrecompileHeaders PROPERTY TIMEOUT ${CMake_TEST_PrecompileHeaders_TIMEOUT})
+endif()
+
 add_RunCMake_test(UnityBuild -DCMake_TEST_OBJC=${CMake_TEST_OBJC} -DCMake_TEST_CUDA=${CMake_TEST_CUDA})
 set_property(TEST RunCMake.UnityBuild APPEND
   PROPERTY LABELS "CUDA")
@@ -1403,3 +1412,7 @@
   add_RunCMake_test(Renesas -DCMake_TEST_Renesas_TOOLCHAINS=${CMake_TEST_Renesas_TOOLCHAINS})
   set_property(TEST RunCMake.Renesas APPEND PROPERTY LABELS "Renesas")
 endif()
+if(CMake_TEST_Emscripten_TOOLCHAINS)
+  add_RunCMake_test(Emscripten -DCMake_TEST_Emscripten_TOOLCHAINS=${CMake_TEST_Emscripten_TOOLCHAINS})
+  set_property(TEST RunCMake.Emscripten APPEND PROPERTY LABELS "Emscripten")
+endif()
diff --git a/Tests/RunCMake/CXXModules/ExportInstallCxxModules.cmake b/Tests/RunCMake/CXXModules/ExportInstallCxxModules.cmake
index 24a32a6..238cda5 100644
--- a/Tests/RunCMake/CXXModules/ExportInstallCxxModules.cmake
+++ b/Tests/RunCMake/CXXModules/ExportInstallCxxModules.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 set(CMAKE_CXX_SCANDEP_SOURCE "")
 
diff --git a/Tests/RunCMake/CXXModules/InstallBMI.cmake b/Tests/RunCMake/CXXModules/InstallBMI.cmake
index f0947b4..d05d4ae 100644
--- a/Tests/RunCMake/CXXModules/InstallBMI.cmake
+++ b/Tests/RunCMake/CXXModules/InstallBMI.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 
 add_library(install-bmi)
diff --git a/Tests/RunCMake/CXXModules/InstallBMIGenericArgs.cmake b/Tests/RunCMake/CXXModules/InstallBMIGenericArgs.cmake
index 8f17143..08e8c37 100644
--- a/Tests/RunCMake/CXXModules/InstallBMIGenericArgs.cmake
+++ b/Tests/RunCMake/CXXModules/InstallBMIGenericArgs.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 
 add_library(install-bmi-generic-args)
diff --git a/Tests/RunCMake/CXXModules/NinjaDependInfoBMIInstall.cmake b/Tests/RunCMake/CXXModules/NinjaDependInfoBMIInstall.cmake
index fd8fd25..7a6a46f 100644
--- a/Tests/RunCMake/CXXModules/NinjaDependInfoBMIInstall.cmake
+++ b/Tests/RunCMake/CXXModules/NinjaDependInfoBMIInstall.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Fake out that we have dyndep; we only need to generate, not actually build
 # here.
 set(CMAKE_CXX_SCANDEP_SOURCE "")
diff --git a/Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase.cmake b/Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase.cmake
index 27daba0..c481f59 100644
--- a/Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase.cmake
+++ b/Tests/RunCMake/CXXModules/NinjaDependInfoCompileDatabase.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Fake out that we have dyndep; we only need to generate, not actually build
 # here.
 set(CMAKE_CXX_SCANDEP_SOURCE "")
diff --git a/Tests/RunCMake/CXXModules/NinjaDependInfoExport.cmake b/Tests/RunCMake/CXXModules/NinjaDependInfoExport.cmake
index a224eca..22ff95f 100644
--- a/Tests/RunCMake/CXXModules/NinjaDependInfoExport.cmake
+++ b/Tests/RunCMake/CXXModules/NinjaDependInfoExport.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Fake out that we have dyndep; we only need to generate, not actually build
 # here.
 set(CMAKE_CXX_SCANDEP_SOURCE "")
diff --git a/Tests/RunCMake/CXXModules/NinjaDependInfoExportFilesystemSafe.cmake b/Tests/RunCMake/CXXModules/NinjaDependInfoExportFilesystemSafe.cmake
index 890b5e4..18e777d 100644
--- a/Tests/RunCMake/CXXModules/NinjaDependInfoExportFilesystemSafe.cmake
+++ b/Tests/RunCMake/CXXModules/NinjaDependInfoExportFilesystemSafe.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Fake out that we have dyndep; we only need to generate, not actually build
 # here.
 set(CMAKE_CXX_SCANDEP_SOURCE "")
diff --git a/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet.cmake b/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet.cmake
index 77351bf..a2c3fe9 100644
--- a/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet.cmake
+++ b/Tests/RunCMake/CXXModules/NinjaDependInfoFileSet.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Fake out that we have dyndep; we only need to generate, not actually build
 # here.
 set(CMAKE_CXX_SCANDEP_SOURCE "")
diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake
index 2b278da..30bade3 100644
--- a/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake
+++ b/Tests/RunCMake/ClangTidy/ExportFixesDir.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 set(CMAKE_C_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
 set(CMAKE_C_CLANG_TIDY_EXPORT_FIXES_DIR clang-tidy)
diff --git a/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake b/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake
index c81c49a..3fab637 100644
--- a/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake
+++ b/Tests/RunCMake/ClangTidy/ExportFixesDir2.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 set(CMAKE_C_CLANG_TIDY "${PSEUDO_TIDY}" -some -args)
 set(CMAKE_C_CLANG_TIDY_EXPORT_FIXES_DIR clang-tidy)
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-OFF.cmake b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-OFF.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-OFF.cmake
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON-stderr.txt b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON-stderr.txt
new file mode 100644
index 0000000..47caf4e
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Warning:
+  The "Visual Studio 14 2015" generator is deprecated and will be removed in
+  a future version of CMake.
+
+  Add CMAKE_WARN_VS14=OFF to the cache to disable this warning.$
diff --git a/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON.cmake b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/DeprecateVS14-WARN-ON.cmake
diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
index 51b7e25..f22ef61 100644
--- a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
+++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt
@@ -1 +1 @@
-^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":8}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":1}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
+^{"debugger":(true|false),"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":9}]},{"kind":"configureLog","version":\[{"major":1,"minor":0}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":1}]},{"kind":"toolchains","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"tls":(true|false),"version":{.*}}$
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-result.txt b/Tests/RunCMake/CommandLine/E_copy_directory_if_newer-nonexistent-source-result.txt
similarity index 100%
rename from Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-result.txt
rename to Tests/RunCMake/CommandLine/E_copy_directory_if_newer-nonexistent-source-result.txt
diff --git a/Tests/RunCMake/CommandLine/E_copy_directory_if_newer-nonexistent-source-stderr.txt b/Tests/RunCMake/CommandLine/E_copy_directory_if_newer-nonexistent-source-stderr.txt
new file mode 100644
index 0000000..248ebb4
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy_directory_if_newer-nonexistent-source-stderr.txt
@@ -0,0 +1 @@
+^Error copying directory from ".+" to ".+"\.$
diff --git a/Tests/RunCMake/CommandLine/E_copy_directory_if_newer-stderr.txt b/Tests/RunCMake/CommandLine/E_copy_directory_if_newer-stderr.txt
new file mode 100644
index 0000000..10f3293
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy_directory_if_newer-stderr.txt
@@ -0,0 +1 @@
+^$
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-result.txt b/Tests/RunCMake/CommandLine/E_copy_if_different-nonexistent-source-result.txt
similarity index 100%
copy from Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-result.txt
copy to Tests/RunCMake/CommandLine/E_copy_if_different-nonexistent-source-result.txt
diff --git a/Tests/RunCMake/CommandLine/E_copy_if_different-nonexistent-source-stderr.txt b/Tests/RunCMake/CommandLine/E_copy_if_different-nonexistent-source-stderr.txt
new file mode 100644
index 0000000..ce1099b
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy_if_different-nonexistent-source-stderr.txt
@@ -0,0 +1 @@
+^Error copying file \(if different\) from ".+" to ".+"\.$
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-result.txt b/Tests/RunCMake/CommandLine/E_copy_if_newer-nonexistent-source-result.txt
similarity index 100%
copy from Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-result.txt
copy to Tests/RunCMake/CommandLine/E_copy_if_newer-nonexistent-source-result.txt
diff --git a/Tests/RunCMake/CommandLine/E_copy_if_newer-nonexistent-source-stderr.txt b/Tests/RunCMake/CommandLine/E_copy_if_newer-nonexistent-source-stderr.txt
new file mode 100644
index 0000000..52e51bc
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy_if_newer-nonexistent-source-stderr.txt
@@ -0,0 +1 @@
+^Error copying file \(if newer\) from ".+" to ".+"\.$
diff --git a/Tests/RunCMake/CommandLine/E_copy_if_newer-one-source-directory-target-is-directory-stderr.txt b/Tests/RunCMake/CommandLine/E_copy_if_newer-one-source-directory-target-is-directory-stderr.txt
new file mode 100644
index 0000000..10f3293
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy_if_newer-one-source-directory-target-is-directory-stderr.txt
@@ -0,0 +1 @@
+^$
diff --git a/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-directory-stderr.txt b/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-directory-stderr.txt
new file mode 100644
index 0000000..10f3293
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-directory-stderr.txt
@@ -0,0 +1 @@
+^$
diff --git a/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-file-result.txt b/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-file-result.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-file-result.txt
diff --git a/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-file-stderr.txt b/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-file-stderr.txt
new file mode 100644
index 0000000..08eab4c
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_copy_if_newer-three-source-files-target-is-file-stderr.txt
@@ -0,0 +1 @@
+^Error: Target \(for copy_if_newer command\).* is not a directory\.$
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index 9fda9eb..ae796d8 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -616,6 +616,16 @@
   ${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${in}/f2.txt ${in}/f3.txt ${out})
 run_cmake_command(E_copy_if_different-three-source-files-target-is-file
   ${CMAKE_COMMAND} -E copy_if_different ${in}/f1.txt ${in}/f2.txt ${in}/f3.txt ${out}/f1.txt)
+run_cmake_command(E_copy_if_different-nonexistent-source
+  ${CMAKE_COMMAND} -E copy_if_different ${in}/nonexistent.txt ${out})
+run_cmake_command(E_copy_if_newer-one-source-directory-target-is-directory
+  ${CMAKE_COMMAND} -E copy_if_newer ${in}/f1.txt ${out})
+run_cmake_command(E_copy_if_newer-three-source-files-target-is-directory
+  ${CMAKE_COMMAND} -E copy_if_newer ${in}/f1.txt ${in}/f2.txt ${in}/f3.txt ${out})
+run_cmake_command(E_copy_if_newer-three-source-files-target-is-file
+  ${CMAKE_COMMAND} -E copy_if_newer ${in}/f1.txt ${in}/f2.txt ${in}/f3.txt ${out}/f1.txt)
+run_cmake_command(E_copy_if_newer-nonexistent-source
+  ${CMAKE_COMMAND} -E copy_if_newer ${in}/nonexistent.txt ${out})
 unset(in)
 unset(out)
 
@@ -625,6 +635,10 @@
 file(MAKE_DIRECTORY ${out})
 run_cmake_command(E_copy_directory_if_different
   ${CMAKE_COMMAND} -E copy_directory_if_different ${in} ${out})
+run_cmake_command(E_copy_directory_if_newer
+  ${CMAKE_COMMAND} -E copy_directory_if_newer ${in} ${out})
+run_cmake_command(E_copy_directory_if_newer-nonexistent-source
+  ${CMAKE_COMMAND} -E copy_directory_if_newer ${in}/nonexistent ${out}/target)
 unset(in)
 unset(out)
 
@@ -1167,3 +1181,10 @@
 endif()
 set(ENV{CMAKE_CONFIG_DIR} cmake_config_dir)
 run_cmake_command(print-config-dir-env ${CMAKE_COMMAND} "--print-config-dir")
+
+if(RunCMake_GENERATOR MATCHES "^Visual Studio 14 2015")
+  run_cmake_with_options(DeprecateVS14-WARN-ON -DCMAKE_WARN_VS14=ON)
+  unset(ENV{CMAKE_WARN_VS14})
+  run_cmake(DeprecateVS14-WARN-ON)
+  run_cmake_with_options(DeprecateVS14-WARN-OFF -DCMAKE_WARN_VS14=OFF)
+endif()
diff --git a/Tests/RunCMake/ConfigDir/check-reply.cmake b/Tests/RunCMake/ConfigDir/check-reply.cmake
index eb534c0..26c5022 100644
--- a/Tests/RunCMake/ConfigDir/check-reply.cmake
+++ b/Tests/RunCMake/ConfigDir/check-reply.cmake
@@ -1,6 +1,6 @@
 if (NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/reply)
   set(RunCMake_TEST_FAILED "Failed to read FileAPI query from user config directory")
 endif()
-if (NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/.cmake/instrumentation-a37d1069-1972-4901-b9c9-f194aaf2b6e0/v1/data)
+if (NOT EXISTS ${RunCMake_TEST_BINARY_DIR}/.cmake/instrumentation-d16a3082-c4e1-489b-b90c-55750a334f27/v1/data)
   set(RunCMake_TEST_FAILED "Failed to read Instrumentation query from user config directory")
 endif()
diff --git a/Tests/RunCMake/ConfigDir/config/instrumentation-a37d1069-1972-4901-b9c9-f194aaf2b6e0/v1/query/query.json b/Tests/RunCMake/ConfigDir/config/instrumentation-d16a3082-c4e1-489b-b90c-55750a334f27/v1/query/query.json
similarity index 100%
rename from Tests/RunCMake/ConfigDir/config/instrumentation-a37d1069-1972-4901-b9c9-f194aaf2b6e0/v1/query/query.json
rename to Tests/RunCMake/ConfigDir/config/instrumentation-d16a3082-c4e1-489b-b90c-55750a334f27/v1/query/query.json
diff --git a/Tests/RunCMake/CpsExportImportBuild/TestLibrary.cmake b/Tests/RunCMake/CpsExportImportBuild/TestLibrary.cmake
index 13e9e01..cdacbc5 100644
--- a/Tests/RunCMake/CpsExportImportBuild/TestLibrary.cmake
+++ b/Tests/RunCMake/CpsExportImportBuild/TestLibrary.cmake
@@ -1,12 +1,33 @@
 project(TestLibrary C)
 
-add_library(liba SHARED liba.c)
-add_library(libb SHARED libb.c)
+add_library(liba SHARED)
+target_sources(liba
+  PRIVATE
+    liba/liba.c
+  INTERFACE
+    FILE_SET HEADERS
+    BASE_DIRS
+      liba
+    FILES
+      liba/liba.h
+)
+
+add_library(libb SHARED)
+target_sources(libb
+  PRIVATE
+    libb/libb.c
+  INTERFACE
+    FILE_SET HEADERS
+    BASE_DIRS
+      libb
+    FILES
+      libb/libb.h
+)
 
 target_link_libraries(libb PUBLIC liba)
 
-install(TARGETS liba EXPORT liba DESTINATION lib)
+install(TARGETS liba EXPORT liba FILE_SET HEADERS)
 export(EXPORT liba PACKAGE_INFO liba)
 
-install(TARGETS libb EXPORT libb DESTINATION lib)
+install(TARGETS libb EXPORT libb FILE_SET HEADERS)
 export(EXPORT libb PACKAGE_INFO libb)
diff --git a/Tests/RunCMake/CpsExportImportBuild/app.c b/Tests/RunCMake/CpsExportImportBuild/app.c
index 9ad7829..036919d 100644
--- a/Tests/RunCMake/CpsExportImportBuild/app.c
+++ b/Tests/RunCMake/CpsExportImportBuild/app.c
@@ -1,11 +1,6 @@
+#include <libb.h>
 #include <stdio.h>
 
-extern
-#ifdef _WIN32
-__declspec(dllimport)
-#endif
-int ask(void);
-
 int main(void)
 {
   printf("%i\n", ask());
diff --git a/Tests/RunCMake/CpsExportImportBuild/liba.c b/Tests/RunCMake/CpsExportImportBuild/liba/liba.c
similarity index 100%
rename from Tests/RunCMake/CpsExportImportBuild/liba.c
rename to Tests/RunCMake/CpsExportImportBuild/liba/liba.c
diff --git a/Tests/RunCMake/CpsExportImportBuild/liba/liba.h b/Tests/RunCMake/CpsExportImportBuild/liba/liba.h
new file mode 100644
index 0000000..55448e5
--- /dev/null
+++ b/Tests/RunCMake/CpsExportImportBuild/liba/liba.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int answer(void);
diff --git a/Tests/RunCMake/CpsExportImportBuild/libb.c b/Tests/RunCMake/CpsExportImportBuild/libb.c
deleted file mode 100644
index 8ba04af..0000000
--- a/Tests/RunCMake/CpsExportImportBuild/libb.c
+++ /dev/null
@@ -1,13 +0,0 @@
-extern
-#ifdef _WIN32
-__declspec(dllimport)
-#endif
-int answer(void);
-
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-int ask(void)
-{
-  return answer();
-}
diff --git a/Tests/RunCMake/CpsExportImportBuild/libb/libb.c b/Tests/RunCMake/CpsExportImportBuild/libb/libb.c
new file mode 100644
index 0000000..e8450c2
--- /dev/null
+++ b/Tests/RunCMake/CpsExportImportBuild/libb/libb.c
@@ -0,0 +1,9 @@
+#include <liba.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int ask(void)
+{
+  return answer();
+}
diff --git a/Tests/RunCMake/CpsExportImportBuild/libb/libb.h b/Tests/RunCMake/CpsExportImportBuild/libb/libb.h
new file mode 100644
index 0000000..d311e68
--- /dev/null
+++ b/Tests/RunCMake/CpsExportImportBuild/libb/libb.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int ask(void);
diff --git a/Tests/RunCMake/CpsExportImportInstall/TestLibrary.cmake b/Tests/RunCMake/CpsExportImportInstall/TestLibrary.cmake
index a984f2b..d59c882 100644
--- a/Tests/RunCMake/CpsExportImportInstall/TestLibrary.cmake
+++ b/Tests/RunCMake/CpsExportImportInstall/TestLibrary.cmake
@@ -2,13 +2,34 @@
 
 set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/../install")
 
-add_library(liba SHARED liba.c)
-add_library(libb SHARED libb.c)
+add_library(liba SHARED)
+target_sources(liba
+  PRIVATE
+    liba/liba.c
+  INTERFACE
+    FILE_SET HEADERS
+    BASE_DIRS
+      liba
+    FILES
+      liba/liba.h
+)
+
+add_library(libb SHARED)
+target_sources(libb
+  PRIVATE
+    libb/libb.c
+  INTERFACE
+    FILE_SET HEADERS
+    BASE_DIRS
+      libb
+    FILES
+      libb/libb.h
+)
 
 target_link_libraries(libb PUBLIC liba)
 
-install(TARGETS liba EXPORT liba DESTINATION lib)
+install(TARGETS liba EXPORT liba FILE_SET HEADERS)
 install(PACKAGE_INFO liba DESTINATION cps EXPORT liba)
 
-install(TARGETS libb EXPORT libb DESTINATION lib)
+install(TARGETS libb EXPORT libb FILE_SET HEADERS)
 install(PACKAGE_INFO libb DESTINATION cps EXPORT libb)
diff --git a/Tests/RunCMake/CpsExportImportInstall/app.c b/Tests/RunCMake/CpsExportImportInstall/app.c
index 9ad7829..036919d 100644
--- a/Tests/RunCMake/CpsExportImportInstall/app.c
+++ b/Tests/RunCMake/CpsExportImportInstall/app.c
@@ -1,11 +1,6 @@
+#include <libb.h>
 #include <stdio.h>
 
-extern
-#ifdef _WIN32
-__declspec(dllimport)
-#endif
-int ask(void);
-
 int main(void)
 {
   printf("%i\n", ask());
diff --git a/Tests/RunCMake/CpsExportImportInstall/liba.c b/Tests/RunCMake/CpsExportImportInstall/liba/liba.c
similarity index 100%
rename from Tests/RunCMake/CpsExportImportInstall/liba.c
rename to Tests/RunCMake/CpsExportImportInstall/liba/liba.c
diff --git a/Tests/RunCMake/CpsExportImportInstall/liba/liba.h b/Tests/RunCMake/CpsExportImportInstall/liba/liba.h
new file mode 100644
index 0000000..55448e5
--- /dev/null
+++ b/Tests/RunCMake/CpsExportImportInstall/liba/liba.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int answer(void);
diff --git a/Tests/RunCMake/CpsExportImportInstall/libb.c b/Tests/RunCMake/CpsExportImportInstall/libb.c
deleted file mode 100644
index 8ba04af..0000000
--- a/Tests/RunCMake/CpsExportImportInstall/libb.c
+++ /dev/null
@@ -1,13 +0,0 @@
-extern
-#ifdef _WIN32
-__declspec(dllimport)
-#endif
-int answer(void);
-
-#ifdef _WIN32
-__declspec(dllexport)
-#endif
-int ask(void)
-{
-  return answer();
-}
diff --git a/Tests/RunCMake/CpsExportImportInstall/libb/libb.c b/Tests/RunCMake/CpsExportImportInstall/libb/libb.c
new file mode 100644
index 0000000..e8450c2
--- /dev/null
+++ b/Tests/RunCMake/CpsExportImportInstall/libb/libb.c
@@ -0,0 +1,9 @@
+#include <liba.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int ask(void)
+{
+  return answer();
+}
diff --git a/Tests/RunCMake/CpsExportImportInstall/libb/libb.h b/Tests/RunCMake/CpsExportImportInstall/libb/libb.h
new file mode 100644
index 0000000..d311e68
--- /dev/null
+++ b/Tests/RunCMake/CpsExportImportInstall/libb/libb.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int ask(void);
diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddTest-CMP0158-OLD.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddTest-CMP0158-OLD.cmake
index e85fd40..4df6298 100644
--- a/Tests/RunCMake/CrosscompilingEmulator/AddTest-CMP0158-OLD.cmake
+++ b/Tests/RunCMake/CrosscompilingEmulator/AddTest-CMP0158-OLD.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_testing()
 if(CMAKE_CROSSCOMPILING)
diff --git a/Tests/RunCMake/CrosscompilingEmulator/AddTest.cmake b/Tests/RunCMake/CrosscompilingEmulator/AddTest.cmake
index 2d169dc..c5e42c8 100644
--- a/Tests/RunCMake/CrosscompilingEmulator/AddTest.cmake
+++ b/Tests/RunCMake/CrosscompilingEmulator/AddTest.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_testing()
 set(CMAKE_CROSSCOMPILING 1)
diff --git a/Tests/RunCMake/Emscripten/CMakeLists.txt b/Tests/RunCMake/Emscripten/CMakeLists.txt
new file mode 100644
index 0000000..955802c
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 4.0)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/Emscripten/RunCMakeTest.cmake b/Tests/RunCMake/Emscripten/RunCMakeTest.cmake
new file mode 100644
index 0000000..efce630
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/RunCMakeTest.cmake
@@ -0,0 +1,66 @@
+include(RunCMake)
+
+# Locate Emscripten toolchain
+if(RunCMake_GENERATOR MATCHES "Makefile|Ninja")
+  file(GLOB _emscripten_toolchains
+    "${CMake_TEST_Emscripten_TOOLCHAINS}/emcc" )
+  if(_emscripten_toolchains STREQUAL "")
+    message(FATAL_ERROR "Could not find any Emscripten toolchains at: ${CMake_TEST_Emscripten_TOOLCHAINS}.")
+  endif()
+endif()
+
+function(run_toolchain case)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
+  run_cmake_with_options(${case} ${ARGN})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .)
+endfunction()
+
+macro(run_cmake_target test subtest target)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(${test}-${subtest}-build ${CMAKE_COMMAND} --build . --target ${target} --config Release --verbose ${ARGN})
+  unset(RunCMake_TEST_BINARY_DIR)
+  unset(RunCMake_TEST_NO_CLEAN)
+endmacro()
+
+foreach(_emscripten_toolchain IN LISTS _emscripten_toolchains)
+  message(STATUS "Found Emscripten toolchain: ${_emscripten_toolchain}")
+  cmake_path(GET _emscripten_toolchain PARENT_PATH BIN_DIR)
+
+  if (WIN32)
+    set(EMCC_SUFFIX ".bat")
+  else()
+    set(EMCC_SUFFIX "")
+  endif()
+
+  set(c_comp ${BIN_DIR}/emcc${EMCC_SUFFIX})
+  set(cxx_comp ${BIN_DIR}/em++${EMCC_SUFFIX})
+  set(comp_ar ${BIN_DIR}/emar${EMCC_SUFFIX})
+
+  # Create an executable from .c sources only.
+  run_toolchain(emscripten-c
+    -DCMAKE_SYSTEM_NAME=Emscripten
+    -DCMAKE_C_COMPILER=${c_comp}
+  )
+
+  # Create an executable from .c and .cxx sources.
+  run_toolchain(emscripten-cxx
+    -DCMAKE_SYSTEM_NAME=Emscripten
+    -DCMAKE_C_COMPILER=${c_comp}
+    -DCMAKE_CXX_COMPILER=${cxx_comp}
+  )
+
+  # Create a library and executable from .c sources.
+  run_toolchain(emscripten-lib
+    -DCMAKE_SYSTEM_NAME=Emscripten
+    -DCMAKE_C_COMPILER=${c_comp}
+  )
+
+  run_cmake_with_options(emscripten-WHOLE_ARCHIVE
+    -DCMAKE_SYSTEM_NAME=Emscripten
+    -DCMAKE_C_COMPILER=${c_comp}
+  )
+  run_cmake_target(emscripten-WHOLE_ARCHIVE link-exe main)
+  run_cmake_target(emscripten-WHOLE_ARCHIVE circular-exe main_circular)
+endforeach()
diff --git a/Tests/RunCMake/Emscripten/base.c b/Tests/RunCMake/Emscripten/base.c
new file mode 100644
index 0000000..ed769a0
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/base.c
@@ -0,0 +1,9 @@
+
+#if !defined(STATIC_BASE)
+#  if defined(_WIN32)
+__declspec(dllexport)
+#  endif
+#endif
+  void base(void)
+{
+}
diff --git a/Tests/RunCMake/Emscripten/circular1.c b/Tests/RunCMake/Emscripten/circular1.c
new file mode 100644
index 0000000..80ee413
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/circular1.c
@@ -0,0 +1,6 @@
+void circular2(void);
+
+void circular1(void)
+{
+  circular2();
+}
diff --git a/Tests/RunCMake/Emscripten/circular2.c b/Tests/RunCMake/Emscripten/circular2.c
new file mode 100644
index 0000000..751bab5
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/circular2.c
@@ -0,0 +1,7 @@
+
+void circular1(void);
+
+void circular2(void)
+{
+  circular1();
+}
diff --git a/Tests/RunCMake/Emscripten/emscripten-WHOLE_ARCHIVE.cmake b/Tests/RunCMake/Emscripten/emscripten-WHOLE_ARCHIVE.cmake
new file mode 100644
index 0000000..e826eae
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/emscripten-WHOLE_ARCHIVE.cmake
@@ -0,0 +1,20 @@
+
+enable_language(C)
+
+add_library(base STATIC base.c unref.c)
+target_compile_definitions(base PUBLIC STATIC_BASE)
+
+add_library(lib SHARED lib.c)
+target_link_libraries(lib PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,base>")
+
+add_executable(main main.c)
+target_link_libraries(main PRIVATE lib)
+
+add_library(circular1 STATIC circular1.c)
+add_library(circular2 STATIC circular2.c)
+
+target_link_libraries(circular1 PRIVATE circular2)
+target_link_libraries(circular2 PRIVATE circular1)
+
+add_executable(main_circular main_circular.c)
+target_link_libraries(main_circular PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,circular1>)
diff --git a/Tests/RunCMake/Emscripten/emscripten-c.cmake b/Tests/RunCMake/Emscripten/emscripten-c.cmake
new file mode 100644
index 0000000..39325a7
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/emscripten-c.cmake
@@ -0,0 +1,2 @@
+enable_language(C)
+add_executable(exec-c module.c)
diff --git a/Tests/RunCMake/Emscripten/emscripten-cxx.cmake b/Tests/RunCMake/Emscripten/emscripten-cxx.cmake
new file mode 100644
index 0000000..9e00aa3
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/emscripten-cxx.cmake
@@ -0,0 +1,2 @@
+enable_language(CXX)
+add_executable(exec-cxx module.cxx)
diff --git a/Tests/RunCMake/Emscripten/emscripten-lib.cmake b/Tests/RunCMake/Emscripten/emscripten-lib.cmake
new file mode 100644
index 0000000..a215d02
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/emscripten-lib.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+add_library(emscripten-test-lib libmod.c)
+
+add_executable(exec-lib-c module.c)
+target_compile_definitions(exec-lib-c PRIVATE __USE_LIBFUN)
+target_link_libraries(exec-lib-c PRIVATE emscripten-test-lib)
diff --git a/Tests/RunCMake/Emscripten/lib.c b/Tests/RunCMake/Emscripten/lib.c
new file mode 100644
index 0000000..21f559c
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/lib.c
@@ -0,0 +1,15 @@
+
+#if !defined(STATIC_BASE)
+#  if defined(_WIN32)
+__declspec(dllimport)
+#  endif
+#endif
+  void base(void);
+
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+  void lib(void)
+{
+  base();
+}
diff --git a/Tests/RunCMake/Emscripten/libmod.c b/Tests/RunCMake/Emscripten/libmod.c
new file mode 100644
index 0000000..b0d3952
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/libmod.c
@@ -0,0 +1,4 @@
+int emscripten_libfun()
+{
+  return 42;
+}
diff --git a/Tests/RunCMake/Emscripten/main.c b/Tests/RunCMake/Emscripten/main.c
new file mode 100644
index 0000000..2e39bce
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/main.c
@@ -0,0 +1,18 @@
+
+#if defined(_WIN32)
+__declspec(dllimport)
+#endif
+  void lib(void);
+
+#if defined(_WIN32)
+__declspec(dllimport)
+#endif
+  void unref(void);
+
+int main(void)
+{
+  lib();
+  unref();
+
+  return 0;
+}
diff --git a/Tests/RunCMake/Emscripten/main_circular.c b/Tests/RunCMake/Emscripten/main_circular.c
new file mode 100644
index 0000000..16ebee6
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/main_circular.c
@@ -0,0 +1,9 @@
+
+void circular1(void);
+
+int main(void)
+{
+  circular1();
+
+  return 0;
+}
diff --git a/Tests/RunCMake/Emscripten/module.c b/Tests/RunCMake/Emscripten/module.c
new file mode 100644
index 0000000..62014fa
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/module.c
@@ -0,0 +1,15 @@
+#include "module.h"
+#if defined(__USE_LIBFUN)
+extern int emscripten_libfun();
+#endif
+
+int i;
+int main()
+{
+#if defined(__USE_LIBFUN)
+  i = emscripten_libfun();
+#else
+  i = INTERNAL;
+#endif
+  return i;
+}
diff --git a/Tests/RunCMake/Emscripten/module.cxx b/Tests/RunCMake/Emscripten/module.cxx
new file mode 100644
index 0000000..b4d46b1
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/module.cxx
@@ -0,0 +1,7 @@
+#include "module.h"
+int i;
+int main()
+{
+  i = INTERNAL;
+  return i;
+}
diff --git a/Tests/RunCMake/Emscripten/module.h b/Tests/RunCMake/Emscripten/module.h
new file mode 100644
index 0000000..a8a85a6
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/module.h
@@ -0,0 +1,12 @@
+#ifndef __MODULE_H__
+#define __MODULE_H__
+
+#if defined(__cplusplus)
+#  define INTERNAL 64
+#elif !defined(__cplusplus)
+#  define INTERNAL 32
+#else
+#  error "Unable to determine INTERNAL symbol."
+#endif
+
+#endif /* __MODULE_H__ */
diff --git a/Tests/RunCMake/Emscripten/unref.c b/Tests/RunCMake/Emscripten/unref.c
new file mode 100644
index 0000000..11922de
--- /dev/null
+++ b/Tests/RunCMake/Emscripten/unref.c
@@ -0,0 +1,8 @@
+
+
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+  void unref(void)
+{
+}
diff --git a/Tests/RunCMake/ExportPackageInfo/Appendix-check.cmake b/Tests/RunCMake/ExportPackageInfo/Appendix-check.cmake
index c4f617f..8d55625 100644
--- a/Tests/RunCMake/ExportPackageInfo/Appendix-check.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Appendix-check.cmake
@@ -5,11 +5,13 @@
 file(READ "${out_dir}/foo.cps" content)
 expect_value("${content}" "foo" "name")
 expect_value("${content}" "interface" "components" "mammal" "type")
+expect_value("${content}" "LGPL-3.0-or-later" "default_license")
 expect_value("${content}" "1.0" "version")
 
 file(READ "${out_dir}/foo-dog.cps" content)
 expect_value("${content}" "foo" "name")
 expect_value("${content}" "interface" "components" "canine" "type")
+expect_value("${content}" "GPL-3.0-or-later" "default_license")
 expect_missing("${content}" "version")
 
 expect_array("${content}" 1 "components" "canine" "requires")
diff --git a/Tests/RunCMake/ExportPackageInfo/Appendix.cmake b/Tests/RunCMake/ExportPackageInfo/Appendix.cmake
index 153231f..51a3c62 100644
--- a/Tests/RunCMake/ExportPackageInfo/Appendix.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Appendix.cmake
@@ -5,5 +5,14 @@
 install(TARGETS mammal EXPORT mammal DESTINATION .)
 install(TARGETS canine EXPORT canine DESTINATION .)
 
-export(EXPORT mammal PACKAGE_INFO foo VERSION 1.0)
-export(EXPORT canine PACKAGE_INFO foo APPENDIX dog)
+export(
+  EXPORT mammal
+  PACKAGE_INFO foo
+  VERSION 1.0
+  DEFAULT_LICENSE "LGPL-3.0-or-later")
+
+export(
+  EXPORT canine
+  PACKAGE_INFO foo
+  APPENDIX dog
+  DEFAULT_LICENSE "GPL-3.0-or-later")
diff --git a/Tests/RunCMake/ExportPackageInfo/BadArgs2-stderr.txt b/Tests/RunCMake/ExportPackageInfo/BadArgs2-stderr.txt
index cc81af4..a811229 100644
--- a/Tests/RunCMake/ExportPackageInfo/BadArgs2-stderr.txt
+++ b/Tests/RunCMake/ExportPackageInfo/BadArgs2-stderr.txt
@@ -5,6 +5,12 @@
 
 
 CMake Error at BadArgs2\.cmake:[0-9]+ \(export\):
+  export APPENDIX and LICENSE are mutually exclusive\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at BadArgs2\.cmake:[0-9]+ \(export\):
   export APPENDIX and DESCRIPTION are mutually exclusive\.
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
diff --git a/Tests/RunCMake/ExportPackageInfo/BadArgs2.cmake b/Tests/RunCMake/ExportPackageInfo/BadArgs2.cmake
index 5f4c949..6058c7f 100644
--- a/Tests/RunCMake/ExportPackageInfo/BadArgs2.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/BadArgs2.cmake
@@ -1,8 +1,10 @@
 add_library(foo INTERFACE)
 install(TARGETS foo EXPORT foo DESTINATION .)
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test VERSION 1.0)
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test DESCRIPTION "Test")
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test HOMEPAGE_URL "example.com")
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test DEFAULT_TARGETS foo)
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test DEFAULT_CONFIGURATIONS Release)
-export(EXPORT foo PACKAGE_INFO foo APPENDIX test PROJECT foo)
+set(args EXPORT foo PACKAGE_INFO foo APPENDIX test)
+export(${args} VERSION 1.0)
+export(${args} LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
+export(${args} DESCRIPTION "Test")
+export(${args} HOMEPAGE_URL "example.com")
+export(${args} DEFAULT_TARGETS foo)
+export(${args} DEFAULT_CONFIGURATIONS Release)
+export(${args} PROJECT foo)
diff --git a/Tests/RunCMake/ExportPackageInfo/BadArgs4-stderr.txt b/Tests/RunCMake/ExportPackageInfo/BadArgs4-stderr.txt
index e21b87e..f4a393c 100644
--- a/Tests/RunCMake/ExportPackageInfo/BadArgs4-stderr.txt
+++ b/Tests/RunCMake/ExportPackageInfo/BadArgs4-stderr.txt
@@ -1,52 +1,64 @@
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export LOWER_CASE_FILE requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "LOWER_CASE_FILE".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
 
 
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export APPENDIX requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "APPENDIX".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
 
 
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export VERSION requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "VERSION".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
 
 
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export DESCRIPTION requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "LICENSE".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
 
 
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export HOMEPAGE_URL requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "DEFAULT_LICENSE".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
 
 
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export DEFAULT_TARGETS requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "DESCRIPTION".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
 
 
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export DEFAULT_CONFIGURATIONS requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "HOMEPAGE_URL".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
 
 
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export PROJECT requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "DEFAULT_TARGETS".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
 
 
 CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
-  export NO_PROJECT_METADATA requires PACKAGE_INFO\.
+  export EXPORT subcommand given unknown argument: "DEFAULT_CONFIGURATIONS".
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
+  export EXPORT subcommand given unknown argument: "PROJECT".
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at BadArgs4\.cmake:[0-9]+ \(export\):
+  export EXPORT subcommand given unknown argument: "NO_PROJECT_METADATA".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
diff --git a/Tests/RunCMake/ExportPackageInfo/BadArgs4.cmake b/Tests/RunCMake/ExportPackageInfo/BadArgs4.cmake
index d8cb163..2405a63 100644
--- a/Tests/RunCMake/ExportPackageInfo/BadArgs4.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/BadArgs4.cmake
@@ -1,11 +1,14 @@
 add_library(foo INTERFACE)
 install(TARGETS foo EXPORT foo DESTINATION .)
-export(EXPORT foo LOWER_CASE_FILE)
-export(EXPORT foo APPENDIX test)
-export(EXPORT foo VERSION 1.0)
-export(EXPORT foo DESCRIPTION "Test")
-export(EXPORT foo HOMEPAGE_URL "example.com")
-export(EXPORT foo DEFAULT_TARGETS foo)
-export(EXPORT foo DEFAULT_CONFIGURATIONS Release)
-export(EXPORT foo PROJECT foo)
-export(EXPORT foo NO_PROJECT_METADATA)
+set(args EXPORT foo)
+export(${args} LOWER_CASE_FILE)
+export(${args} APPENDIX test)
+export(${args} VERSION 1.0)
+export(${args} LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
+export(${args} DEFAULT_LICENSE "BSD-3-Clause")
+export(${args} DESCRIPTION "Test")
+export(${args} HOMEPAGE_URL "example.com")
+export(${args} DEFAULT_TARGETS foo)
+export(${args} DEFAULT_CONFIGURATIONS Release)
+export(${args} PROJECT foo)
+export(${args} NO_PROJECT_METADATA)
diff --git a/Tests/RunCMake/ExportPackageInfo/PerConfigGeneration-check.cmake b/Tests/RunCMake/ExportPackageInfo/Config-check.cmake
similarity index 65%
rename from Tests/RunCMake/ExportPackageInfo/PerConfigGeneration-check.cmake
rename to Tests/RunCMake/ExportPackageInfo/Config-check.cmake
index 221942f..acb4ecd 100644
--- a/Tests/RunCMake/ExportPackageInfo/PerConfigGeneration-check.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Config-check.cmake
@@ -1,14 +1,14 @@
 include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
 
-set(out_dir "${RunCMake_BINARY_DIR}/PerConfigGeneration-build")
+set(out_dir "${RunCMake_BINARY_DIR}/Config-build")
 
 file(READ "${out_dir}/foo.cps" content)
 
 if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  foreach(config ${CMAKE_CONFIGURATION_TYPES})
+  foreach(config FooConfig BarConfig)
     expect_object("${content}" "components" "foo" "configurations" ${config})
   endforeach()
 else()
-  include(${RunCMake_TEST_BINARY_DIR}/build_type.cmake)
+  set(config TestConfig)
   expect_object("${content}" "components" "foo" "configurations" ${config})
 endif()
diff --git a/Tests/RunCMake/ExportPackageInfo/Config.cmake b/Tests/RunCMake/ExportPackageInfo/Config.cmake
new file mode 100644
index 0000000..361fb66
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/Config.cmake
@@ -0,0 +1,13 @@
+project(Config CXX)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  set(CMAKE_CONFIGURATION_TYPES "FooConfig;BarConfig" CACHE STRING "" FORCE)
+else()
+  set(CMAKE_BUILD_TYPE "TestConfig" CACHE STRING "" FORCE)
+endif()
+
+add_library(foo foo.cxx)
+
+install(TARGETS foo EXPORT foo)
+export(EXPORT foo PACKAGE_INFO foo)
diff --git a/Tests/RunCMake/ExportPackageInfo/DependencyVersionCMake-check.cmake b/Tests/RunCMake/ExportPackageInfo/DependencyVersionCMake-check.cmake
new file mode 100644
index 0000000..e4822b7
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/DependencyVersionCMake-check.cmake
@@ -0,0 +1,15 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/DependencyVersionCMake-build")
+
+file(READ "${out_dir}/foo.cps" content)
+expect_value("${content}" "foo" "name")
+expect_array("${content}" 1 "requires" "bar" "components")
+expect_value("${content}" "bar" "requires" "bar" "components" 0)
+expect_value("${content}" "1.3.5" "requires" "bar" "version")
+expect_array("${content}" 1 "requires" "bar" "hints")
+expect_value("${content}" "${CMAKE_CURRENT_LIST_DIR}/config" "requires" "bar" "hints" 0)
+
+string(JSON component GET "${content}" "components" "foo")
+expect_array("${component}" 1 "requires")
+expect_value("${component}" "bar:bar" "requires" 0)
diff --git a/Tests/RunCMake/ExportPackageInfo/DependencyVersionCMake.cmake b/Tests/RunCMake/ExportPackageInfo/DependencyVersionCMake.cmake
new file mode 100644
index 0000000..e82a16e
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/DependencyVersionCMake.cmake
@@ -0,0 +1,11 @@
+find_package(
+    bar 1.3.4 REQUIRED CONFIG
+    NO_DEFAULT_PATH
+    PATHS ${CMAKE_CURRENT_LIST_DIR}/config
+)
+
+add_library(foo INTERFACE)
+target_link_libraries(foo INTERFACE bar::bar)
+
+install(TARGETS foo EXPORT foo DESTINATION .)
+export(EXPORT foo PACKAGE_INFO foo)
diff --git a/Tests/RunCMake/ExportPackageInfo/DependencyVersionCps-check.cmake b/Tests/RunCMake/ExportPackageInfo/DependencyVersionCps-check.cmake
new file mode 100644
index 0000000..0b84ec1
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/DependencyVersionCps-check.cmake
@@ -0,0 +1,15 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/DependencyVersionCps-build/")
+
+file(READ "${out_dir}/foo.cps" content)
+expect_value("${content}" "foo" "name")
+expect_array("${content}" 1 "requires" "baz" "components")
+expect_value("${content}" "baz" "requires" "baz" "components" 0)
+expect_value("${content}" "1.3.5" "requires" "baz" "version")
+expect_array("${content}" 1 "requires" "baz" "hints")
+expect_value("${content}" "${CMAKE_CURRENT_LIST_DIR}/cps" "requires" "baz" "hints" 0)
+
+string(JSON component GET "${content}" "components" "foo")
+expect_array("${component}" 1 "requires")
+expect_value("${component}" "baz:baz" "requires" 0)
diff --git a/Tests/RunCMake/ExportPackageInfo/DependencyVersionCps.cmake b/Tests/RunCMake/ExportPackageInfo/DependencyVersionCps.cmake
new file mode 100644
index 0000000..97cf54f
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/DependencyVersionCps.cmake
@@ -0,0 +1,11 @@
+find_package(
+    baz 1.3.4 REQUIRED
+    NO_DEFAULT_PATH
+    PATHS ${CMAKE_CURRENT_LIST_DIR}
+)
+
+add_library(foo INTERFACE)
+target_link_libraries(foo INTERFACE baz::baz)
+
+install(TARGETS foo EXPORT foo DESTINATION .)
+export(EXPORT foo PACKAGE_INFO foo)
diff --git a/Tests/RunCMake/ExportPackageInfo/EmptyConfig-check.cmake b/Tests/RunCMake/ExportPackageInfo/EmptyConfig-check.cmake
new file mode 100644
index 0000000..ffabf80
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/EmptyConfig-check.cmake
@@ -0,0 +1,7 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/EmptyConfig-build")
+
+file(READ "${out_dir}/foo.cps" content)
+
+expect_object("${content}" "components" "foo" "configurations" "noconfig")
diff --git a/Tests/RunCMake/ExportPackageInfo/EmptyConfig.cmake b/Tests/RunCMake/ExportPackageInfo/EmptyConfig.cmake
new file mode 100644
index 0000000..4ed6436
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/EmptyConfig.cmake
@@ -0,0 +1,9 @@
+project(EmptyConfig CXX)
+
+set(CMAKE_BUILD_TYPE "" CACHE STRING "" FORCE)
+set(CMAKE_CONFIGURATION_TYPES "" CACHE STRING "" FORCE)
+
+add_library(foo foo.cxx)
+
+install(TARGETS foo EXPORT foo)
+export(EXPORT foo PACKAGE_INFO foo)
diff --git a/Tests/RunCMake/ExportPackageInfo/ExperimentalGate-stderr.txt b/Tests/RunCMake/ExportPackageInfo/ExperimentalGate-stderr.txt
index 36725b3..1d0930f 100644
--- a/Tests/RunCMake/ExportPackageInfo/ExperimentalGate-stderr.txt
+++ b/Tests/RunCMake/ExportPackageInfo/ExperimentalGate-stderr.txt
@@ -1,2 +1,2 @@
 CMake Error at ExperimentalGate.cmake:5 \(export\):
-  export Unknown argument: "PACKAGE_INFO"\.
+  export EXPORT subcommand given unknown argument: "PACKAGE_INFO".
diff --git a/Tests/RunCMake/ExportPackageInfo/FileSetHeaders-check.cmake b/Tests/RunCMake/ExportPackageInfo/FileSetHeaders-check.cmake
new file mode 100644
index 0000000..60f5820
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/FileSetHeaders-check.cmake
@@ -0,0 +1,10 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/FileSetHeaders-build")
+
+file(READ "${out_dir}/foo.cps" content)
+
+string(JSON component GET "${content}" "components" "foo")
+
+expect_array("${component}" 1 "includes")
+expect_value("${component}" "${CMAKE_CURRENT_LIST_DIR}/foo" "includes" 0)
diff --git a/Tests/RunCMake/ExportPackageInfo/FileSetHeaders.cmake b/Tests/RunCMake/ExportPackageInfo/FileSetHeaders.cmake
new file mode 100644
index 0000000..6b6fdf8
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/FileSetHeaders.cmake
@@ -0,0 +1,29 @@
+add_library(foo INTERFACE)
+
+# Primarily this tests for de-duplication of the BASE_DIRS, ensuring DESTINATION
+# genex have no effect on build exports is a bonus covering a very unlikely bug
+
+target_sources(foo
+  INTERFACE
+    FILE_SET no_genex
+    TYPE HEADERS
+    BASE_DIRS ${CMAKE_CURRENT_LIST_DIR}/foo
+
+  INTERFACE
+    FILE_SET genex
+    TYPE HEADERS
+    BASE_DIRS ${CMAKE_CURRENT_LIST_DIR}/foo
+)
+
+install(
+  TARGETS foo
+  EXPORT foo
+  DESTINATION .
+
+  FILE_SET no_genex
+    DESTINATION no_genex
+
+  FILE_SET genex
+    DESTINATION $<$<CONFIG:FAKE_CONFIG>:FAKE_DEST>genex
+)
+export(EXPORT foo PACKAGE_INFO foo)
diff --git a/Tests/RunCMake/ExportPackageInfo/Metadata-check.cmake b/Tests/RunCMake/ExportPackageInfo/Metadata-check.cmake
index f9b3cc7..438a76c 100644
--- a/Tests/RunCMake/ExportPackageInfo/Metadata-check.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Metadata-check.cmake
@@ -15,5 +15,7 @@
 expect_value("${content}" "release" "configurations" 0)
 expect_value("${content}" "debug" "configurations" 1)
 
+expect_value("${content}" "BSD-3-Clause" "default_license")
+expect_value("${content}" "BSD-3-Clause AND CC-BY-SA-4.0" "license")
 expect_value("${content}" "Sample package" "description")
 expect_value("${content}" "https://www.example.com/package/foo" "website")
diff --git a/Tests/RunCMake/ExportPackageInfo/Metadata.cmake b/Tests/RunCMake/ExportPackageInfo/Metadata.cmake
index 2311695..4f3bd16 100644
--- a/Tests/RunCMake/ExportPackageInfo/Metadata.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/Metadata.cmake
@@ -8,6 +8,8 @@
   COMPAT_VERSION 1.2.0
   DEFAULT_TARGETS foo
   DEFAULT_CONFIGURATIONS release debug
+  LICENSE "BSD-3-Clause AND CC-BY-SA-4.0"
+  DEFAULT_LICENSE "BSD-3-Clause"
   DESCRIPTION "Sample package"
   HOMEPAGE_URL "https://www.example.com/package/foo"
   )
diff --git a/Tests/RunCMake/ExportPackageInfo/PerConfigGeneration.cmake b/Tests/RunCMake/ExportPackageInfo/PerConfigGeneration.cmake
deleted file mode 100644
index ed9b29a..0000000
--- a/Tests/RunCMake/ExportPackageInfo/PerConfigGeneration.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-project(PerConfigGeneration CXX)
-
-set(config ${CMAKE_BUILD_TYPE})
-if(NOT config)
-  set(config noconfig)
-endif()
-
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/build_type.cmake" "set(config \"${config}\")")
-
-add_library(foo foo.cxx)
-
-install(TARGETS foo EXPORT foo)
-export(EXPORT foo PACKAGE_INFO foo)
diff --git a/Tests/RunCMake/ExportPackageInfo/ProjectMetadata-check.cmake b/Tests/RunCMake/ExportPackageInfo/ProjectMetadata-check.cmake
index 1330099..c7201f8 100644
--- a/Tests/RunCMake/ExportPackageInfo/ProjectMetadata-check.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/ProjectMetadata-check.cmake
@@ -6,6 +6,7 @@
 expect_value("${content}" "foo" "name")
 expect_value("${content}" "1.2.3" "version")
 expect_value("${content}" "1.1.0" "compat_version")
+expect_value("${content}" "BSD-3-Clause" "license")
 expect_value("${content}" "Sample package" "description")
 expect_value("${content}" "https://www.example.com/package/foo" "website")
 
@@ -13,6 +14,7 @@
 expect_value("${content}" "test1" "name")
 expect_value("${content}" "1.2.3" "version")
 expect_value("${content}" "1.1.0" "compat_version")
+expect_value("${content}" "BSD-3-Clause" "license")
 expect_value("${content}" "Sample package" "description")
 expect_value("${content}" "https://www.example.com/package/foo" "website")
 
@@ -20,5 +22,6 @@
 expect_value("${content}" "test2" "name")
 expect_value("${content}" "1.4.7" "version")
 expect_missing("${content}" "compat_version")
+expect_value("${content}" "Apache-2.0" "license")
 expect_value("${content}" "Don't inherit" "description")
 expect_value("${content}" "https://www.example.com/package/bar" "website")
diff --git a/Tests/RunCMake/ExportPackageInfo/ProjectMetadata.cmake b/Tests/RunCMake/ExportPackageInfo/ProjectMetadata.cmake
index f53ba0e..07352d7 100644
--- a/Tests/RunCMake/ExportPackageInfo/ProjectMetadata.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/ProjectMetadata.cmake
@@ -1,6 +1,7 @@
 project(foo
   VERSION 1.2.3
   COMPAT_VERSION 1.1.0
+  SPDX_LICENSE "BSD-3-Clause"
   DESCRIPTION "Sample package"
   HOMEPAGE_URL "https://www.example.com/package/foo"
   )
@@ -17,16 +18,16 @@
 # Test inheriting from a specified project.
 export(
   EXPORT foo
-  PROJECT foo
-  PACKAGE_INFO test1
+  PACKAGE_INFO test1 PROJECT foo
   )
 
 # Test that inheriting doesn't override explicitly specified metadata.
 export(
   EXPORT foo
-  PROJECT foo
   PACKAGE_INFO test2
+  PROJECT foo
   VERSION 1.4.7
+  LICENSE "Apache-2.0"
   DESCRIPTION "Don't inherit"
   HOMEPAGE_URL "https://www.example.com/package/bar"
   )
diff --git a/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake
index 6fee4ac..45c4397 100644
--- a/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ExportPackageInfo/RunCMakeTest.cmake
@@ -8,6 +8,7 @@
 set(RunCMake_TEST_OPTIONS
   -Wno-dev
   "-DCMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO:STRING=b80be207-778e-46ba-8080-b23bba22639e"
+  "-DCMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES:STRING=e82e467b-f997-4464-8ace-b00808fff261"
   )
 
 # Test incorrect usage
@@ -40,4 +41,8 @@
 run_cmake(TargetTypes)
 run_cmake(DependsMultiple)
 run_cmake(LinkOnly)
-run_cmake(PerConfigGeneration)
+run_cmake(Config)
+run_cmake(EmptyConfig)
+run_cmake(FileSetHeaders)
+run_cmake(DependencyVersionCMake)
+run_cmake(DependencyVersionCps)
diff --git a/Tests/RunCMake/ExportPackageInfo/config/bar-config-version.cmake b/Tests/RunCMake/ExportPackageInfo/config/bar-config-version.cmake
new file mode 100644
index 0000000..ff683d6
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/config/bar-config-version.cmake
@@ -0,0 +1,29 @@
+set(PACKAGE_VERSION "1.3.5")
+
+if (PACKAGE_FIND_VERSION_RANGE)
+  # Check for a version range
+  if (PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_RANGE_MIN)
+    set(PACKAGE_VERSION_COMPATIBLE FALSE)
+  else ()
+    if (PACKAGE_FIND_VERSION_RANGE_MAX)
+      if (PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_RANGE_MAX)
+        set(PACKAGE_VERSION_COMPATIBLE FALSE)
+      else ()
+        set(PACKAGE_VERSION_COMPATIBLE TRUE)
+      endif ()
+    else ()
+      set(PACKAGE_VERSION_COMPATIBLE TRUE)
+    endif ()
+  endif ()
+
+elseif (PACKAGE_FIND_VERSION)
+  # Check for a specific version or minimum version
+  if (PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+    set(PACKAGE_VERSION_COMPATIBLE FALSE)
+  else ()
+    set(PACKAGE_VERSION_COMPATIBLE TRUE)
+    if (PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION)
+      set(PACKAGE_VERSION_EXACT TRUE)
+    endif ()
+  endif ()
+endif ()
diff --git a/Tests/RunCMake/ExportPackageInfo/config/bar-config.cmake b/Tests/RunCMake/ExportPackageInfo/config/bar-config.cmake
new file mode 100644
index 0000000..d17ed84
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/config/bar-config.cmake
@@ -0,0 +1 @@
+add_library(bar::bar INTERFACE IMPORTED)
diff --git a/Tests/RunCMake/ExportPackageInfo/cps/baz.cps b/Tests/RunCMake/ExportPackageInfo/cps/baz.cps
new file mode 100644
index 0000000..6cf1042
--- /dev/null
+++ b/Tests/RunCMake/ExportPackageInfo/cps/baz.cps
@@ -0,0 +1,14 @@
+{
+  "components" :
+  {
+    "baz" :
+    {
+      "type" : "interface"
+    }
+  },
+  "cps_path" : "@prefix@/cps",
+  "cps_version" : "0.13.0",
+  "compat_version": "1.0.0",
+  "name" : "baz",
+  "version": "1.3.5"
+}
diff --git a/Tests/RunCMake/ExternalProject/EnvVars-build-stdout.txt b/Tests/RunCMake/ExternalProject/EnvVars-build-stdout.txt
new file mode 100644
index 0000000..d3d6d2c
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/EnvVars-build-stdout.txt
@@ -0,0 +1,32 @@
+.*(Performing custom step for 'CustomCommandEnvVars'|CustomCommandEnvVars-custom).*
+ *-- Variable - CustomVar: custom.*
+ *-- Variable - CustomVar2: custom2.*
+ *-- Stage: custom
+ *-- Separator: ;
+ *-- List: 1;2;3
+.*(Performing configure step for 'CustomCommandEnvVars'|CustomCommandEnvVars-configure).*
+ *-- Stage: config
+ *-- Separator: ;
+ *-- List: 4;5;6.*
+ *-- Variable - Stage: config.*
+ *-- Variable - ListVar: 4;5;6
+.*(Performing build step for 'CustomCommandEnvVars'|CustomCommandEnvVars-build).*
+ *-- Stage: build
+ *-- Separator: ;
+ *-- List: 4;5;6
+.*(Performing install step for 'CustomCommandEnvVars'|CustomCommandEnvVars-install).*
+ *-- Stage: install
+ *-- Separator: ;
+ *-- List: 4;5;6
+.*(Performing test step for 'CustomCommandEnvVars'|CustomCommandEnvVars-test).*
+ *-- Stage: test
+ *-- Separator: ;
+ *-- List: 4;5;6
+.*(Performing configure step for 'DefaultCommandEnvVars'|DefaultCommandEnvVars-configure).*
+ *-- ConfigVar: config
+ *-- Separator: ,
+ *-- List: 7,8,9
+.*(Performing build step for 'DefaultCommandEnvVars'|DefaultCommandEnvVars-build).*
+ *-- Stage: build
+ *-- Separator: ,
+ *-- List: 7,8,9,10
diff --git a/Tests/RunCMake/ExternalProject/EnvVars.cmake b/Tests/RunCMake/ExternalProject/EnvVars.cmake
new file mode 100644
index 0000000..23994d9
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/EnvVars.cmake
@@ -0,0 +1,104 @@
+include(ExternalProject)
+
+#
+## Set environment variables on custom commands
+#
+
+# Comma list-separator
+set(ScriptPath "${CMAKE_CURRENT_SOURCE_DIR}/EnvVars/EchoVar.cmake")
+ExternalProject_Add(CustomCommandEnvVars
+  DOWNLOAD_COMMAND ""
+  UPDATE_COMMAND ""
+  PATCH_COMMAND ""
+  LIST_SEPARATOR ,
+  CONFIGURE_COMMAND ""
+  COMMAND "${CMAKE_COMMAND}" -P ${ScriptPath}
+  COMMAND "${CMAKE_COMMAND}" -DVARNAME=Stage -P ${ScriptPath}
+  COMMAND ""
+  COMMAND "${CMAKE_COMMAND}" -DVARNAME=ListVar -P ${ScriptPath}
+  CONFIGURE_ENVIRONMENT_MODIFICATION
+    Stage=set:config
+    ListVar=set:4,5,6
+    ListSeparator=set:,
+  BUILD_COMMAND "${CMAKE_COMMAND}" -P ${ScriptPath}
+  BUILD_ENVIRONMENT_MODIFICATION
+    Stage=set:build
+    ListVar=set:4,5,6
+    ListSeparator=set:,
+  INSTALL_COMMAND "${CMAKE_COMMAND}" -P ${ScriptPath}
+  INSTALL_ENVIRONMENT_MODIFICATION
+    InstallVar=set:install
+    Stage=set:install
+    ListVar=set:4,5,6
+    ListSeparator=set:,
+  TEST_COMMAND "${CMAKE_COMMAND}" -P ${ScriptPath}
+  TEST_ENVIRONMENT_MODIFICATION
+    Stage=set:test
+    ListVar=set:4,5,6
+    ListSeparator=set:,)
+
+ExternalProject_Add_Step(CustomCommandEnvVars custom
+  DEPENDERS configure
+  COMMAND "${CMAKE_COMMAND}" -DVARNAME=CustomVar -P ${ScriptPath}
+  COMMAND "${CMAKE_COMMAND}" -DVARNAME=CustomVar2 -P ${ScriptPath}
+  COMMAND "${CMAKE_COMMAND}" -P ${ScriptPath}
+  ENVIRONMENT_MODIFICATION
+    CustomVar=set:custom
+    CustomVar2=set:custom2
+    Stage=set:custom
+    ListVar=set:1,2,3
+    ListSeparator=set:,)
+
+#
+## Set environment variables on the default commands
+#
+
+# No list separator
+ExternalProject_Add(DefaultCommandEnvVars
+  SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/EnvVars"
+  DOWNLOAD_COMMAND ""
+  UPDATE_COMMAND ""
+  PATCH_COMMAND ""
+  DEPENDS CustomCommandEnvVars
+  CMAKE_ARGS
+    -DVARIABLE=ConfigVar
+  CONFIGURE_ENVIRONMENT_MODIFICATION
+    ConfigVar=set:config
+    ListVar=set:7,8,9
+    ListSeparator=set:,
+  BUILD_ENVIRONMENT_MODIFICATION
+    Stage=set:build
+    ListVar=set:7,8,9,10
+    ListSeparator=set:,
+  INSTALL_COMMAND ""                 # empty install command should not show up
+  INSTALL_ENVIRONMENT_MODIFICATION
+    Stage=set:install
+    Separator=set:,)
+
+# Using `:` as a list separator on Windows does not work as it replaces the `:`
+# between the drive letter and the filepath with `;`.
+if(NOT WIN32)
+  # Ensure that using `:` as a list-separator does not break setting environment
+  # variables
+  ExternalProject_Add(DefaultCommandListSepEnvVars
+    SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/EnvVars"
+    DOWNLOAD_COMMAND ""
+    UPDATE_COMMAND ""
+    PATCH_COMMAND ""
+    DEPENDS DefaultCommandEnvVars
+    LIST_SEPARATOR :
+    CMAKE_ARGS
+      -DVARIABLE=ConfigVar
+    CONFIGURE_ENVIRONMENT_MODIFICATION
+      ConfigVar=set:config
+      ListVar=set:10:11:12
+      ListSeparator=set::
+    BUILD_ENVIRONMENT_MODIFICATION
+      Stage=set:build
+      ListVar=set:10:11:12
+      ListSeparator=set::
+    INSTALL_ENVIRONMENT_MODIFICATION
+      Stage=set:install
+      ListSeparator=set::
+      ListVar=set:10:11:12:13)
+endif()
diff --git a/Tests/RunCMake/ExternalProject/EnvVars/CMakeLists.txt b/Tests/RunCMake/ExternalProject/EnvVars/CMakeLists.txt
new file mode 100644
index 0000000..59f0309
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/EnvVars/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 4.0)
+
+project(EnvVars LANGUAGES NONE)
+
+message(STATUS "${VARIABLE}: $ENV{${VARIABLE}}")
+message(STATUS "Separator: $ENV{ListSeparator}")
+message(STATUS "List: $ENV{ListVar}")
+
+add_custom_target(EchoEnvVars ALL COMMAND
+  "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_SOURCE_DIR}/EchoVar.cmake")
+
+install(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/EchoVar.cmake")
diff --git a/Tests/RunCMake/ExternalProject/EnvVars/EchoVar.cmake b/Tests/RunCMake/ExternalProject/EnvVars/EchoVar.cmake
new file mode 100644
index 0000000..e8cbfcf
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/EnvVars/EchoVar.cmake
@@ -0,0 +1,7 @@
+if(VARNAME)
+  message(STATUS "Variable - ${VARNAME}: $ENV{${VARNAME}}")
+else()
+  message(STATUS "Stage: $ENV{Stage}")
+  message(STATUS "Separator: $ENV{ListSeparator}")
+  message(STATUS "List: $ENV{ListVar}")
+endif()
diff --git a/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake b/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake
index a00908b..6f3db4d 100644
--- a/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake
+++ b/Tests/RunCMake/ExternalProject/FetchGitRefs.cmake
@@ -47,6 +47,7 @@
 execGitCommand(-c init.defaultBranch=master init)
 execGitCommand(config --add user.email "testauthor@cmake.org")
 execGitCommand(config --add user.name testauthor)
+execGitCommand(config commit.gpgsign "false")
 
 # Create the initial repo structure
 execGitCommand(add firstFile.txt)
diff --git a/Tests/RunCMake/ExternalProject/GNUMakeJobServerAware.cmake b/Tests/RunCMake/ExternalProject/GNUMakeJobServerAware.cmake
index 077b929..c468be3 100644
--- a/Tests/RunCMake/ExternalProject/GNUMakeJobServerAware.cmake
+++ b/Tests/RunCMake/ExternalProject/GNUMakeJobServerAware.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 include(ExternalProject)
 ExternalProject_Add(Foo
   SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Foo
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/ExternalProject/InvalidEnvModification-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/ExternalProject/InvalidEnvModification-result.txt
diff --git a/Tests/RunCMake/ExternalProject/InvalidEnvModification-stderr.txt b/Tests/RunCMake/ExternalProject/InvalidEnvModification-stderr.txt
new file mode 100644
index 0000000..2925117
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/InvalidEnvModification-stderr.txt
@@ -0,0 +1,6 @@
+.* Malformed environment modification specifier: 'HI'
+.* Expected MYVAR=OP:VALUE
+.* Malformed environment modification specifier: 'INVALID=SETTING'
+.* Expected MYVAR=OP:VALUE
+.* Malformed environment modification specifier: 'INVALID=OP1:operation:10'
+.* Expected MYVAR=OP:VALUE
diff --git a/Tests/RunCMake/ExternalProject/InvalidEnvModification.cmake b/Tests/RunCMake/ExternalProject/InvalidEnvModification.cmake
new file mode 100644
index 0000000..96dfa14
--- /dev/null
+++ b/Tests/RunCMake/ExternalProject/InvalidEnvModification.cmake
@@ -0,0 +1,12 @@
+include(ExternalProject)
+
+ExternalProject_Add(EnvModification
+  SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/EnvVars"
+  DOWNLOAD_COMMAND ""
+  UPDATE_COMMAND ""
+  PATCH_COMMAND ""
+  LIST_SEPARATOR :
+  CONFIGURE_ENVIRONMENT_MODIFICATION
+    HI
+    INVALID=SETTING
+    INVALID=OP1:operation:10)
diff --git a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
index 98e3996..6186292 100644
--- a/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ExternalProject/RunCMakeTest.cmake
@@ -259,3 +259,8 @@
   run_cmake(TLSVersionBadVar)
   run_cmake(TLSVersionBadEnv)
 endif()
+
+set(RunCMake_TEST_OUTPUT_MERGE 1)
+__ep_test_with_build(EnvVars)
+unset(RunCMake_TEST_OUTPUT_MERGE)
+run_cmake(InvalidEnvModification)
diff --git a/Tests/RunCMake/FileAPI/ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/ClientStateful-check.cmake
index e4a1bb2..cbf36eb 100644
--- a/Tests/RunCMake/FileAPI/ClientStateful-check.cmake
+++ b/Tests/RunCMake/FileAPI/ClientStateful-check.cmake
@@ -65,4 +65,13 @@
   )
 check_api("^${expect}$")
 
+check_stateful_queries(
+  request-version-1
+  request-version-1-1
+  request-version-2
+  request-array-version-1
+  request-array-version-1-1
+  request-array-version-2
+)
+
 check_python(ClientStateful index)
diff --git a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
index bf9354e..cf668da 100644
--- a/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
+++ b/Tests/RunCMake/FileAPI/RunCMakeTest.cmake
@@ -1,5 +1,33 @@
 include(RunCMake)
 
+cmake_policy(SET CMP0140 NEW)
+
+# Arguments after the first are the files to validate against the schema
+function(validate_fileapi_schema schema)
+  if(NOT ARGN)
+    # No files to validate against the schema
+    return()
+  endif()
+  list(JOIN ARGN "\n" file_list)
+  set(file_list_file ${RunCMake_TEST_BINARY_DIR}/check_file_list.txt)
+  file(WRITE "${file_list_file}" "${file_list}")
+  execute_process(
+    COMMAND ${Python_EXECUTABLE}
+      "${RunCMake_SOURCE_DIR}/fileapi_validate_schema.py"
+        "${file_list_file}"
+        "${schema}"
+    RESULT_VARIABLE result
+    OUTPUT_VARIABLE output
+    ERROR_VARIABLE output
+  )
+  if(NOT result STREQUAL 0)
+    string(REPLACE "\n" "\n  " output "${output}")
+    string(APPEND RunCMake_TEST_FAILED
+      "Failed to validate files against JSON schema: ${schema}\nOutput:\n${output}\n")
+  endif()
+  return(PROPAGATE RunCMake_TEST_FAILED)
+endfunction()
+
 # Function called in *-check.cmake scripts to check api files.
 function(check_api expect)
   file(GLOB_RECURSE actual
@@ -13,8 +41,65 @@
 do not match what we expected:
   ${expect}
 in directory:
-  ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1" PARENT_SCOPE)
+  ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1")
   endif()
+  if(NOT RunCMake_TEST_FAILED AND Python_EXECUTABLE AND CMake_TEST_JSON_SCHEMA)
+    cmake_path(SET schema_dir NORMALIZE ${RunCMake_SOURCE_DIR}/../../../Help/manual/file_api)
+    set(prefix ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1)
+    set(replies ${actual})
+    list(FILTER replies INCLUDE REGEX "^reply/")
+    set(schema_types
+      index   # Special case, error replies also use this schema
+      codemodel
+      directory
+      target
+      configureLog
+      cache
+      cmakeFiles
+      toolchains
+    )
+    foreach(schema_type IN LISTS schema_types)
+      set(schema_type_${schema_type} "")
+    endforeach()
+    foreach(file IN LISTS replies)
+      if(file MATCHES "^reply/(index|error)-")
+        list(APPEND schema_type_index ${prefix}/${file})
+      else()
+        foreach(schema_type IN LISTS schema_types)
+          if(file MATCHES "^reply/${schema_type}-")
+            list(APPEND schema_type_${schema_type} ${prefix}/${file})
+          endif()
+        endforeach()
+      endif()
+    endforeach()
+    foreach(schema_type IN LISTS schema_types)
+      validate_fileapi_schema(
+        ${schema_dir}/schema_${schema_type}.json
+        ${schema_type_${schema_type}}
+      )
+    endforeach()
+  endif()
+  return(PROPAGATE RunCMake_TEST_FAILED)
+endfunction()
+
+function(check_stateful_queries)
+  if(RunCMake_TEST_FAILED OR NOT Python_EXECUTABLE OR NOT CMake_TEST_JSON_SCHEMA)
+    return()
+  endif()
+
+  cmake_path(SET schema_dir NORMALIZE
+    ${RunCMake_SOURCE_DIR}/../../../Help/manual/file_api
+  )
+  set(prefix ${RunCMake_TEST_BINARY_DIR}/.cmake/api/v1/query/client)
+  list(TRANSFORM ARGN
+    REPLACE "^(.+)$" "${prefix}-\\1/query.json"
+    OUTPUT_VARIABLE query_json_files
+  )
+  validate_fileapi_schema(
+    ${schema_dir}/schema_stateful_query.json
+    ${query_json_files}
+  )
+  return(PROPAGATE RunCMake_TEST_FAILED)
 endfunction()
 
 function(check_python case prefix)
diff --git a/Tests/RunCMake/FileAPI/cache-v2-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/cache-v2-ClientStateful-check.cmake
index f7c9a73..49daf21 100644
--- a/Tests/RunCMake/FileAPI/cache-v2-ClientStateful-check.cmake
+++ b/Tests/RunCMake/FileAPI/cache-v2-ClientStateful-check.cmake
@@ -8,4 +8,6 @@
   )
 check_api("^${expect}$")
 
+check_stateful_queries(foo)
+
 check_python(cache-v2 index)
diff --git a/Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateful-check.cmake
index bcb3fa1..55c8a9d 100644
--- a/Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateful-check.cmake
+++ b/Tests/RunCMake/FileAPI/cmakeFiles-v1-ClientStateful-check.cmake
@@ -8,4 +8,6 @@
   )
 check_api("^${expect}$")
 
+check_stateful_queries(foo)
+
 check_python(cmakeFiles-v1 index)
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
index aa6eeec..9661c82 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-ClientStateful-check.cmake
@@ -10,4 +10,6 @@
   )
 check_api("^${expect}$")
 
+check_stateful_queries(foo)
+
 check_python(codemodel-v2 index)
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
index b7b0090..84b452a 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py
@@ -12,7 +12,9 @@
 def check_objects(o, g):
     assert is_list(o)
     assert len(o) == 1
-    check_index_object(o[0], "codemodel", 2, 8, check_object_codemodel(g))
+    major = 2
+    minor = 9
+    check_index_object(o[0], "codemodel", major, minor, check_object_codemodel(g, major, minor))
 
 def check_backtrace(t, b, backtrace):
     btg = t["backtraceGraph"]
@@ -52,7 +54,7 @@
         check_backtrace(t, actual[i], expected[i])
         i += 1
 
-def check_directory(c):
+def check_directory(c, major, minor):
     def _check(actual, expected):
         assert is_dict(actual)
         expected_keys = ["build", "jsonFile", "source", "projectIndex"]
@@ -100,7 +102,12 @@
             d = json.load(f)
 
         assert is_dict(d)
-        assert sorted(d.keys()) == ["backtraceGraph", "installers", "paths"]
+        assert sorted(d.keys()) == ["backtraceGraph", "codemodelVersion", "installers", "paths"]
+
+        # We get the values for major and minor directly rather than from the "expected" data.
+        # This avoids having to update every data file any time the major or minor version changes.
+        assert is_int(d["codemodelVersion"]["major"], major)
+        assert is_int(d["codemodelVersion"]["minor"], minor)
 
         assert is_string(d["paths"]["source"], actual["source"])
         assert is_string(d["paths"]["build"], actual["build"])
@@ -266,7 +273,7 @@
 
         assert sorted(n.keys()) == sorted(expected_keys)
 
-def check_target(c):
+def check_target(c, major, minor):
     def _check(actual, expected):
         assert is_dict(actual)
         assert sorted(actual.keys()) == ["directoryIndex", "id", "jsonFile", "name", "projectIndex"]
@@ -281,7 +288,7 @@
         with open(filepath) as f:
             obj = json.load(f)
 
-        expected_keys = ["name", "id", "type", "backtraceGraph", "paths", "sources"]
+        expected_keys = ["codemodelVersion", "name", "id", "type", "backtraceGraph", "paths", "sources"]
         assert is_dict(obj)
         assert is_string(obj["name"], expected["name"])
         assert matches(obj["id"], expected["id"])
@@ -293,6 +300,13 @@
         assert matches(obj["paths"]["build"], expected["build"])
         assert matches(obj["paths"]["source"], expected["source"])
 
+        # We get the values for major and minor directly rather than from the "expected" data.
+        # This avoids having to update every data file any time the major or minor version changes.
+        assert is_dict(obj["codemodelVersion"])
+        assert sorted(obj["codemodelVersion"].keys()) == ["major", "minor"]
+        assert is_int(obj["codemodelVersion"]["major"], major)
+        assert is_int(obj["codemodelVersion"]["minor"], minor)
+
         def check_file_set(actual, expected):
             assert is_dict(actual)
             expected_keys = ["name", "type", "visibility", "baseDirectories"]
@@ -794,9 +808,9 @@
 
     return expected
 
-def check_directories(c, g):
+def check_directories(c, g, major, minor):
     check_list_match(lambda a, e: matches(a["source"], e["source"]), c["directories"], gen_check_directories(c, g),
-                     check=check_directory(c),
+                     check=check_directory(c, major, minor),
                      check_exception=lambda a, e: "Directory source: %s" % a["source"],
                      missing_exception=lambda e: "Directory source: %s" % e["source"],
                      extra_exception=lambda a: "Directory source: %s" % a["source"])
@@ -1001,10 +1015,10 @@
 
     return expected
 
-def check_targets(c, g, inSource):
+def check_targets(c, g, major, minor, inSource):
     check_list_match(lambda a, e: matches(a["id"], e["id"]),
                      c["targets"], gen_check_targets(c, g, inSource),
-                     check=check_target(c),
+                     check=check_target(c, major, minor),
                      check_exception=lambda a, e: "Target ID: %s" % a["id"],
                      missing_exception=lambda e: "Target ID: %s" % e["id"],
                      extra_exception=lambda a: "Target ID: %s" % a["id"])
@@ -1045,14 +1059,14 @@
                      missing_exception=lambda e: "Project name: %s" % e["name"],
                      extra_exception=lambda a: "Project name: %s" % a["name"])
 
-def check_object_codemodel_configuration(c, g, inSource):
+def check_object_codemodel_configuration(c, g, major, minor, inSource):
     assert sorted(c.keys()) == ["directories", "name", "projects", "targets"]
     assert is_string(c["name"])
-    check_directories(c, g)
-    check_targets(c, g, inSource)
+    check_directories(c, g, major, minor)
+    check_targets(c, g, major, minor, inSource)
     check_projects(c, g)
 
-def check_object_codemodel(g):
+def check_object_codemodel(g, major, minor):
     def _check(o):
         assert sorted(o.keys()) == ["configurations", "kind", "paths", "version"]
         # The "kind" and "version" members are handled by check_index_object.
@@ -1070,7 +1084,7 @@
             assert o["configurations"][0]["name"] in ("", "Debug", "Release", "RelWithDebInfo", "MinSizeRel")
 
         for c in o["configurations"]:
-            check_object_codemodel_configuration(c, g, inSource)
+            check_object_codemodel_configuration(c, g, major, minor, inSource)
     return _check
 
 cxx_compiler_id = sys.argv[2]
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
index f535822..a72eb1d 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/top.json
@@ -51,7 +51,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 46,
+                    "line": 48,
                     "command": "install",
                     "hasParent": true
                 },
@@ -96,7 +96,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 49,
+                    "line": 51,
                     "command": "install",
                     "hasParent": true
                 },
@@ -144,7 +144,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 49,
+                    "line": 51,
                     "command": "install",
                     "hasParent": true
                 },
@@ -189,7 +189,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 49,
+                    "line": 51,
                     "command": "install",
                     "hasParent": true
                 },
@@ -233,7 +233,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 49,
+                    "line": 51,
                     "command": "install",
                     "hasParent": true
                 },
@@ -277,7 +277,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 54,
+                    "line": 56,
                     "command": "install",
                     "hasParent": true
                 },
@@ -324,7 +324,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 56,
+                    "line": 58,
                     "command": "install",
                     "hasParent": true
                 },
@@ -369,7 +369,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 57,
+                    "line": 59,
                     "command": "install",
                     "hasParent": true
                 },
@@ -418,7 +418,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 58,
+                    "line": 60,
                     "command": "install",
                     "hasParent": true
                 },
@@ -470,7 +470,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 59,
+                    "line": 61,
                     "command": "install",
                     "hasParent": true
                 },
@@ -519,7 +519,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 60,
+                    "line": 62,
                     "command": "install",
                     "hasParent": true
                 },
@@ -561,7 +561,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 61,
+                    "line": 63,
                     "command": "install",
                     "hasParent": true
                 },
@@ -603,7 +603,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 62,
+                    "line": 64,
                     "command": "install",
                     "hasParent": true
                 },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json
index 34e1cbf..2defdaa 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_exe.json
@@ -16,7 +16,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 8,
+                    "line": 10,
                     "command": "add_executable",
                     "hasParent": true
                 },
@@ -64,7 +64,7 @@
     "backtrace": [
         {
             "file": "^codemodel-v2\\.cmake$",
-            "line": 8,
+            "line": 10,
             "command": "add_executable",
             "hasParent": true
         },
@@ -114,7 +114,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 9,
+                    "line": 11,
                     "command": "target_link_libraries",
                     "hasParent": true
                 },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json
index 4a0a43d..04452c4 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_lib.json
@@ -16,7 +16,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 7,
+                    "line": 9,
                     "command": "add_library",
                     "hasParent": true
                 },
@@ -64,7 +64,7 @@
     "backtrace": [
         {
             "file": "^codemodel-v2\\.cmake$",
-            "line": 7,
+            "line": 9,
             "command": "add_library",
             "hasParent": true
         },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json
index ad34f88..a9350a1 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_exe.json
@@ -16,7 +16,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 13,
+                    "line": 15,
                     "command": "add_executable",
                     "hasParent": true
                 },
@@ -64,7 +64,7 @@
     "backtrace": [
         {
             "file": "^codemodel-v2\\.cmake$",
-            "line": 13,
+            "line": 15,
             "command": "add_executable",
             "hasParent": true
         },
@@ -114,7 +114,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 14,
+                    "line": 16,
                     "command": "target_link_libraries",
                     "hasParent": true
                 },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
index 9eee3dc..9bfa73b 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_shared_lib.json
@@ -16,7 +16,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 12,
+                    "line": 14,
                     "command": "add_library",
                     "hasParent": true
                 },
@@ -69,7 +69,7 @@
     "backtrace": [
         {
             "file": "^codemodel-v2\\.cmake$",
-            "line": 12,
+            "line": 14,
             "command": "add_library",
             "hasParent": true
         },
@@ -118,7 +118,7 @@
                 "backtrace": [
                     {
                         "file": "^codemodel-v2\\.cmake$",
-                        "line": 49,
+                        "line": 51,
                         "command": "install",
                         "hasParent": true
                     },
@@ -148,7 +148,7 @@
                 "backtrace": [
                     {
                         "file": "^codemodel-v2\\.cmake$",
-                        "line": 49,
+                        "line": 51,
                         "command": "install",
                         "hasParent": true
                     },
@@ -178,7 +178,7 @@
                 "backtrace": [
                     {
                         "file": "^codemodel-v2\\.cmake$",
-                        "line": 54,
+                        "line": 56,
                         "command": "install",
                         "hasParent": true
                     },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json
index badeeb2..f872b4c 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_exe.json
@@ -16,7 +16,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 17,
+                    "line": 19,
                     "command": "add_executable",
                     "hasParent": true
                 },
@@ -64,7 +64,7 @@
     "backtrace": [
         {
             "file": "^codemodel-v2\\.cmake$",
-            "line": 17,
+            "line": 19,
             "command": "add_executable",
             "hasParent": true
         },
@@ -114,7 +114,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 18,
+                    "line": 20,
                     "command": "target_link_libraries",
                     "hasParent": true
                 },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json
index a05cf59..7d7ab8d 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_static_lib.json
@@ -16,7 +16,7 @@
             "backtrace": [
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 16,
+                    "line": 18,
                     "command": "add_library",
                     "hasParent": true
                 },
@@ -64,7 +64,7 @@
     "backtrace": [
         {
             "file": "^codemodel-v2\\.cmake$",
-            "line": 16,
+            "line": 18,
             "command": "add_library",
             "hasParent": true
         },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json
index 95c5e64..3ffdbac 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/c_subdir.json
@@ -89,7 +89,7 @@
     "backtrace": [
         {
             "file": "^codemodel-v2\\.cmake$",
-            "line": 20,
+            "line": 22,
             "command": "add_library",
             "hasParent": true
         },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
index 68ec736..86d70d6 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_exe.json
@@ -139,7 +139,7 @@
                 "backtrace": [
                     {
                         "file": "^codemodel-v2\\.cmake$",
-                        "line": 46,
+                        "line": 48,
                         "command": "install",
                         "hasParent": true
                     },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
index 45894c0..5318b52 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_shared_lib.json
@@ -94,7 +94,7 @@
                 "backtrace": [
                     {
                         "file": "^codemodel-v2\\.cmake$",
-                        "line": 49,
+                        "line": 51,
                         "command": "install",
                         "hasParent": true
                     },
@@ -124,7 +124,7 @@
                 "backtrace": [
                     {
                         "file": "^codemodel-v2\\.cmake$",
-                        "line": 49,
+                        "line": 51,
                         "command": "install",
                         "hasParent": true
                     },
@@ -154,7 +154,7 @@
                 "backtrace": [
                     {
                         "file": "^codemodel-v2\\.cmake$",
-                        "line": 54,
+                        "line": 56,
                         "command": "install",
                         "hasParent": true
                     },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json
index e737de5..acd7d59 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json
+++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/interface_exe.json
@@ -28,7 +28,7 @@
                 },
                 {
                     "file": "^codemodel-v2\\.cmake$",
-                    "line": 5,
+                    "line": 7,
                     "command": "include",
                     "hasParent": true
                 },
@@ -91,7 +91,7 @@
                         },
                         {
                             "file": "^codemodel-v2\\.cmake$",
-                            "line": 5,
+                            "line": 7,
                             "command": "include",
                             "hasParent": true
                         },
@@ -134,7 +134,7 @@
         },
         {
             "file": "^codemodel-v2\\.cmake$",
-            "line": 5,
+            "line": 7,
             "command": "include",
             "hasParent": true
         },
diff --git a/Tests/RunCMake/FileAPI/codemodel-v2.cmake b/Tests/RunCMake/FileAPI/codemodel-v2.cmake
index d2c3378..1c411f5 100644
--- a/Tests/RunCMake/FileAPI/codemodel-v2.cmake
+++ b/Tests/RunCMake/FileAPI/codemodel-v2.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 set(CMAKE_AIX_SHARED_LIBRARY_ARCHIVE 0)
diff --git a/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-check.cmake
index 2cc4a7b..d951ed0 100644
--- a/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-check.cmake
+++ b/Tests/RunCMake/FileAPI/configureLog-v1-ClientStateful-check.cmake
@@ -8,4 +8,6 @@
   )
 check_api("^${expect}$")
 
+check_stateful_queries(foo)
+
 check_python(configureLog-v1 index)
diff --git a/Tests/RunCMake/FileAPI/fileapi_validate_schema.py b/Tests/RunCMake/FileAPI/fileapi_validate_schema.py
new file mode 100644
index 0000000..8156a46
--- /dev/null
+++ b/Tests/RunCMake/FileAPI/fileapi_validate_schema.py
@@ -0,0 +1,23 @@
+import json
+import jsonschema
+import sys
+
+
+# First argument is a file containing the list of files to check
+with open(sys.argv[1], "r", encoding="utf-8") as file_list:
+    files_to_check = [line.strip() for line in file_list if line.strip()]
+
+# Second argument is the schema file
+with open(sys.argv[2], "r", encoding="utf-8-sig") as f:
+    schema = json.load(f)
+
+# Check each file against the schema
+for file_path in files_to_check:
+    try:
+        with open(file_path, "r", encoding="utf-8-sig") as f:
+            contents = json.load(f)
+        # The following raises an exception if validation fails
+        jsonschema.validate(contents, schema)
+    except Exception as e:
+        print(f"Failed to validate file {file_path}: {e}")
+        raise
diff --git a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake
index dc701de..026170f 100644
--- a/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake
+++ b/Tests/RunCMake/FileAPI/toolchains-v1-ClientStateful-check.cmake
@@ -8,4 +8,6 @@
   )
 check_api("^${expect}$")
 
+check_stateful_queries(foo)
+
 check_python(toolchains-v1 index)
diff --git a/Tests/RunCMake/FindOpenSSL/version-exact.cmake b/Tests/RunCMake/FindOpenSSL/version-exact.cmake
index 367028b..16cde30 100644
--- a/Tests/RunCMake/FindOpenSSL/version-exact.cmake
+++ b/Tests/RunCMake/FindOpenSSL/version-exact.cmake
@@ -1,13 +1,13 @@
 find_package (OpenSSL REQUIRED COMPONENTS Crypto)
 # Store version without a possibly trailing letter.
-string (REGEX MATCH "^([0-9.]+)" version "${OPENSSL_VERSION}")
+string (REGEX MATCH "^([0-9.]+)" version "${OpenSSL_VERSION}")
 
 # clean-up OpenSSL variables
 unset (OPENSSL_INCLUDE_DIR)
 unset (OPENSSL_CRYPTO_LIBRARY)
 unset (OPENSSL_CRYPTO_LIBRARIES)
 unset (OPENSSL_LIBRARIES)
-unset (OPENSSL_VERSION)
+unset (OpenSSL_VERSION)
 unset (OpenSSL_FOUND)
 
 
diff --git a/Tests/RunCMake/FindOpenSSL/version-range.cmake b/Tests/RunCMake/FindOpenSSL/version-range.cmake
index 0180f8b..fcea538 100644
--- a/Tests/RunCMake/FindOpenSSL/version-range.cmake
+++ b/Tests/RunCMake/FindOpenSSL/version-range.cmake
@@ -1,13 +1,13 @@
 find_package (OpenSSL REQUIRED COMPONENTS Crypto)
 # Store version without a possibly trailing letter.
-string (REGEX MATCH "^([0-9.]+)" version "${OPENSSL_VERSION}")
+string (REGEX MATCH "^([0-9.]+)" version "${OpenSSL_VERSION}")
 
 # clean-up OpenSSL variables
 unset (OPENSSL_INCLUDE_DIR)
 unset (OPENSSL_CRYPTO_LIBRARY)
 unset (OPENSSL_CRYPTO_LIBRARIES)
 unset (OPENSSL_LIBRARIES)
-unset (OPENSSL_VERSION)
+unset (OpenSSL_VERSION)
 unset (OpenSSL_FOUND)
 
 ## Specify a range including current OpenSSL version
@@ -24,7 +24,7 @@
 unset (OPENSSL_CRYPTO_LIBRARY)
 unset (OPENSSL_CRYPTO_LIBRARIES)
 unset (OPENSSL_LIBRARIES)
-unset (OPENSSL_VERSION)
+unset (OpenSSL_VERSION)
 unset (OpenSSL_FOUND)
 
 ## Specify a range excluding current OpenSSL version
diff --git a/Tests/RunCMake/FindOpenSSL/version.cmake b/Tests/RunCMake/FindOpenSSL/version.cmake
index f69f3ac..c19a49a 100644
--- a/Tests/RunCMake/FindOpenSSL/version.cmake
+++ b/Tests/RunCMake/FindOpenSSL/version.cmake
@@ -1,13 +1,13 @@
 find_package (OpenSSL REQUIRED COMPONENTS Crypto)
 # Store version without a possibly trailing letter.
-string (REGEX MATCH "^([0-9.]+)" version "${OPENSSL_VERSION}")
+string (REGEX MATCH "^([0-9.]+)" version "${OpenSSL_VERSION}")
 
 # clean-up OpenSSL variables
 unset (OPENSSL_INCLUDE_DIR)
 unset (OPENSSL_CRYPTO_LIBRARY)
 unset (OPENSSL_CRYPTO_LIBRARIES)
 unset (OPENSSL_LIBRARIES)
-unset (OPENSSL_VERSION)
+unset (OpenSSL_VERSION)
 unset (OpenSSL_FOUND)
 
 
diff --git a/Tests/RunCMake/GeneratorExpression/CMP0199-NEW.cmake b/Tests/RunCMake/GeneratorExpression/CMP0199-NEW.cmake
new file mode 100644
index 0000000..5c1dd39
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/CMP0199-NEW.cmake
@@ -0,0 +1,10 @@
+project(test-CMP0199-NEW C)
+
+cmake_policy(SET CMP0199 NEW)
+
+include(CMP0199-cases.cmake)
+
+# FIXME: CMake currently incorrectly selects the RELEASE configuration. See
+# https://gitlab.kitware.com/cmake/cmake/-/issues/27022.
+do_mapped_config_test(EXPECT_RELEASE)
+do_unique_config_test(EXPECT_DEBUG)
diff --git a/Tests/RunCMake/GeneratorExpression/CMP0199-OLD.cmake b/Tests/RunCMake/GeneratorExpression/CMP0199-OLD.cmake
new file mode 100644
index 0000000..d670697
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/CMP0199-OLD.cmake
@@ -0,0 +1,8 @@
+project(test-CMP0199-OLD C)
+
+cmake_policy(SET CMP0199 OLD)
+
+include(CMP0199-cases.cmake)
+
+do_mapped_config_test(EXPECT_RELEASE EXPECT_DEBUG EXPECT_TEST)
+do_unique_config_test(EXPECT_RELEASE EXPECT_DEBUG)
diff --git a/Tests/RunCMake/GeneratorExpression/CMP0199-WARN-stderr.txt b/Tests/RunCMake/GeneratorExpression/CMP0199-WARN-stderr.txt
new file mode 100644
index 0000000..2c5dfbd
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/CMP0199-WARN-stderr.txt
@@ -0,0 +1,11 @@
+CMake Warning \(dev\) at CMP0199-WARN\.cmake:[0-9]+ \(target_link_libraries\):
+  Policy CMP0199 is not set: \$<CONFIG:cfgs> only matches the configuration of
+  the consumed target\.  Run "cmake --help-policy CMP0199" for policy details\.
+  Use the cmake_policy command to set the policy and suppress this warning\.
+
+  Evaluation of \$<CONFIG> for imported target "lib_test", used by "exe_test",
+  may match multiple configurations\.
+
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.
diff --git a/Tests/RunCMake/GeneratorExpression/CMP0199-WARN.cmake b/Tests/RunCMake/GeneratorExpression/CMP0199-WARN.cmake
new file mode 100644
index 0000000..38b2e62
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/CMP0199-WARN.cmake
@@ -0,0 +1,11 @@
+project(test-CMP0199-WARN C)
+
+set(CMAKE_POLICY_WARNING_CMP0199 ON)
+
+add_library(lib_test INTERFACE IMPORTED)
+set_target_properties(lib_test PROPERTIES
+  INTERFACE_COMPILE_DEFINITIONS "$<$<CONFIG:release>:RELEASE>"
+)
+
+add_executable(exe_test configtest.c)
+target_link_libraries(exe_test PRIVATE lib_test)
diff --git a/Tests/RunCMake/GeneratorExpression/CMP0199-cases.cmake b/Tests/RunCMake/GeneratorExpression/CMP0199-cases.cmake
new file mode 100644
index 0000000..591e52e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/CMP0199-cases.cmake
@@ -0,0 +1,32 @@
+# Under CMP0199 OLD, $<CONFIG> matches not just the selected configuration, but
+# every entry in MAP_IMPORTED_CONFIG_<CONFIG>. Under NEW, it should only match
+# the selected configuration.
+function(do_mapped_config_test)
+  add_library(lib_mapped INTERFACE IMPORTED)
+  set_target_properties(lib_mapped PROPERTIES
+    IMPORTED_CONFIGURATIONS "TEST"
+    INTERFACE_COMPILE_DEFINITIONS
+      "$<$<CONFIG:debug>:DEBUG>;$<$<CONFIG:release>:RELEASE>;$<$<CONFIG:test>:TEST>"
+    MAP_IMPORTED_CONFIG_RELEASE "RELEASE;DEBUG;TEST"
+  )
+
+  add_executable(exe_mapped configtest.c)
+  target_compile_definitions(exe_mapped PRIVATE ${ARGN})
+  target_link_libraries(exe_mapped PRIVATE lib_mapped)
+endfunction()
+
+# Under CMake CMP0199 OLD, $<CONFIG> matches both the consumer's configuration
+# AND the selected configuration of the library being consumed. Under NEW, it
+# should only match the selected configuration.
+function(do_unique_config_test)
+  add_library(lib_unique INTERFACE IMPORTED)
+  set_target_properties(lib_unique PROPERTIES
+    IMPORTED_CONFIGURATIONS "DEBUG"
+    INTERFACE_COMPILE_DEFINITIONS
+      "$<$<CONFIG:debug>:DEBUG>;$<$<CONFIG:release>:RELEASE>"
+  )
+
+  add_executable(exe_unique configtest.c)
+  target_compile_definitions(exe_unique PRIVATE ${ARGN})
+  target_link_libraries(exe_unique PRIVATE lib_unique)
+endfunction()
diff --git a/Tests/RunCMake/GeneratorExpression/COMPILER_LINKER.cmake b/Tests/RunCMake/GeneratorExpression/COMPILER_LINKER.cmake
new file mode 100644
index 0000000..aedf6e4
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/COMPILER_LINKER.cmake
@@ -0,0 +1,19 @@
+
+set(languages C ${LANG})
+list(REMOVE_DUPLICATES languages)
+
+enable_language(${languages})
+
+include(CTest)
+
+set(VAR "${CMAKE_${LANG}_COMPILER_LINKER_${TYPE}}")
+if(NOT VAR)
+  set(VAR "UNDEF")
+endif()
+
+add_executable(COMPILER_LINKER compiler_linker.c)
+target_compile_definitions(COMPILER_LINKER PRIVATE "VAR=${VAR}"
+                                                   "GENEX=$<IF:$<BOOL:$<${LANG}_COMPILER_LINKER_${TYPE}>>,$<${LANG}_COMPILER_LINKER_${TYPE}>,UNDEF>")
+
+add_test(NAME COMPILER_LINKER.${LANG}.${TYPE}
+         COMMAND COMPILER_LINKER)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..35285fc
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<C_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<C_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary targets.
+  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.ID-stderr.txt
new file mode 100644
index 0000000..b68ff04
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.C.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<C_COMPILER_LINKER_ID>
+
+  \$<C_COMPILER_LINKER_ID> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..796707f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<CUDA_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<CUDA_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.ID-stderr.txt
new file mode 100644
index 0000000..d5a67a6
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CUDA.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<CUDA_COMPILER_LINKER_ID>
+
+  \$<CUDA_COMPILER_LINKER_ID> may only be used with binary targets.  It may
+  not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..818c506
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<CXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<CXX_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.ID-stderr.txt
new file mode 100644
index 0000000..b3e9636
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.CXX.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<CXX_COMPILER_LINKER_ID>
+
+  \$<CXX_COMPILER_LINKER_ID> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..5271aa2
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<Fortran_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<Fortran_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.ID-stderr.txt
new file mode 100644
index 0000000..fba2c28
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.Fortran.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<Fortran_COMPILER_LINKER_ID>
+
+  \$<Fortran_COMPILER_LINKER_ID> may only be used with binary targets.  It may
+  not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..a260a01
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<HIP_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<HIP_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.ID-stderr.txt
new file mode 100644
index 0000000..da64b4e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.HIP.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<HIP_COMPILER_LINKER_ID>
+
+  \$<HIP_COMPILER_LINKER_ID> may only be used with binary targets.  It may not
+  be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..80aee3e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OBJC_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<OBJC_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.ID-stderr.txt
new file mode 100644
index 0000000..c23c539
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJC.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OBJC_COMPILER_LINKER_ID>
+
+  \$<OBJC_COMPILER_LINKER_ID> may only be used with binary targets.  It may
+  not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.FRONTEND_VARIANT-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.FRONTEND_VARIANT-stderr.txt
new file mode 100644
index 0000000..506a48b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.FRONTEND_VARIANT-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT>
+
+  \$<OBJCXX_COMPILER_LINKER_FRONTEND_VARIANT> may only be used with binary
+  targets.  It may not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.ID-stderr.txt b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.ID-stderr.txt
new file mode 100644
index 0000000..7160ef7
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.OBJCXX.ID-stderr.txt
@@ -0,0 +1,9 @@
+CMake Error at NonValidTarget-COMPILER_LINKER.cmake:[0-9]+ \(add_custom_command\):
+  Error evaluating generator expression:
+
+    \$<OBJCXX_COMPILER_LINKER_ID>
+
+  \$<OBJCXX_COMPILER_LINKER_ID> may only be used with binary targets.  It may
+  not be used with add_custom_command or add_custom_target.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.cmake b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.cmake
new file mode 100644
index 0000000..0853e72
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/NonValidTarget-COMPILER_LINKER.cmake
@@ -0,0 +1,4 @@
+add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/copied_file.c"
+  COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/empty.c" "${CMAKE_CURRENT_BINARY_DIR}/copied_file$<${LANG}_COMPILER_LINKER_${TYPE}>.c"
+)
+add_custom_target(drive DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/copied_file.c")
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index 985d91b..0c68d39 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -48,6 +48,63 @@
 run_cmake(FILTER-Exclude)
 run_cmake(FILTER-Include)
 
+function(run_cmake_build test)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test}-build)
+  if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_CONFIGURATION_TYPES=Release)
+  else()
+    list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Release)
+  endif()
+
+  run_cmake(${test})
+
+  set(RunCMake_TEST_NO_CLEAN TRUE)
+  run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Release)
+endfunction()
+
+function(run_linker_genex test lang type)
+  set(options_args CHECK_RESULT EXECUTE)
+  cmake_parse_arguments(PARSE_ARGV 3 RLG "${options_args}" "" "")
+
+  set(RunCMake_TEST_VARIANT_DESCRIPTION ".${lang}.${type}")
+  set(test_name ${test}${RunCMake_TEST_VARIANT_DESCRIPTION})
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${test_name}-build")
+  if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    list(APPEND options -DCMAKE_BUILD_TYPE=Release)
+  endif()
+  if(RLG_CHECK_RESULT)
+    set(RunCMake_TEST_EXPECT_RESULT 1)
+    file(READ "${RunCMake_SOURCE_DIR}/${test_name}-stderr.txt" RunCMake_TEST_EXPECT_stderr)
+  endif()
+  run_cmake_with_options(${test} -DLANG=${lang} -DTYPE=${type})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  unset(RunCMake_TEST_VARIANT_DESCRIPTION)
+  if(RLG_EXECUTE)
+    run_cmake_command(${test_name}-build "${CMAKE_COMMAND}" --build . --config Release)
+    run_cmake_command(${test_name}-run "${CMAKE_CTEST_COMMAND}" -C Release -V)
+  endif()
+endfunction()
+function(exec_linker_genex test lang type)
+  run_linker_genex(${ARGV} EXECUTE)
+endfunction()
+
+set(languages C CXX)
+foreach(lang IN ITEMS OBJC Fortran CUDA HIP)
+  if(CMake_TEST_${lang})
+    list(APPEND languages ${lang})
+    if(lang STREQUAL OBJC)
+    list(APPEND languages OBJCXX)
+    endif()
+  endif()
+endforeach()
+
+foreach(lang IN LISTS languages)
+  foreach(type IN ITEMS ID FRONTEND_VARIANT)
+    run_linker_genex(NonValidTarget-COMPILER_LINKER ${lang} ${type} CHECK_RESULT)
+    exec_linker_genex(COMPILER_LINKER ${lang} ${type})
+  endforeach()
+endforeach()
+
 if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
   set(RunCMake_TEST_OPTIONS [==[-DCMAKE_CONFIGURATION_TYPES=CustomConfig]==])
 else()
@@ -60,6 +117,11 @@
   set(RunCMake_TEST_OPTIONS [==[-DCMAKE_BUILD_TYPE=]==])
 endif()
 run_cmake(CONFIG-empty-entries)
+unset(RunCMake_TEST_OPTIONS)
+
+run_cmake(CMP0199-WARN)
+run_cmake_build(CMP0199-OLD)
+run_cmake_build(CMP0199-NEW)
 
 set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0085:STRING=OLD)
 run_cmake(CMP0085-OLD)
diff --git a/Tests/RunCMake/GeneratorExpression/compiler_linker.c b/Tests/RunCMake/GeneratorExpression/compiler_linker.c
new file mode 100644
index 0000000..db9a5f4
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/compiler_linker.c
@@ -0,0 +1,10 @@
+
+#include <string.h>
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+int main(void)
+{
+  return strcmp(xstr(VAR), xstr(GENEX)) == 0 ? 0 : 1;
+}
diff --git a/Tests/RunCMake/GeneratorExpression/configtest.c b/Tests/RunCMake/GeneratorExpression/configtest.c
new file mode 100644
index 0000000..94e357e
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/configtest.c
@@ -0,0 +1,34 @@
+#ifdef EXPECT_DEBUG
+#  ifndef DEBUG
+#    error DEBUG should be defined
+#  endif
+#else
+#  ifdef DEBUG
+#    error DEBUG should not be defined
+#  endif
+#endif
+
+#ifdef EXPECT_RELEASE
+#  ifndef RELEASE
+#    error RELEASE should be defined
+#  endif
+#else
+#  ifdef RELEASE
+#    error RELEASE should not be defined
+#  endif
+#endif
+
+#ifdef EXPECT_TEST
+#  ifndef TEST
+#    error TEST should be defined
+#  endif
+#else
+#  ifdef TEST
+#    error TEST should not be defined
+#  endif
+#endif
+
+int main(void)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-DEF_SOURCE_LINE-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-DEF_SOURCE_LINE-stdout.txt
new file mode 100644
index 0000000..c42463b
--- /dev/null
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-DEF_SOURCE_LINE-stdout.txt
@@ -0,0 +1,8 @@
+.*"tests" *:.*
+ *"name" *: *"basic.case_foo" *,.*
+ *"name" *: *"DEF_SOURCE_LINE", *
+ *"value" *: *"file1.cpp:1" *
+.*
+ *"name" *: *"basic.case_bar" *,.*
+ *"name" *: *"DEF_SOURCE_LINE", *
+ *"value" *: *"file with spaces.cpp:2" *
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-typed-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-typed-stdout.txt
index d4b4fcf..a658586 100644
--- a/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-typed-stdout.txt
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change-typed-stdout.txt
@@ -1,12 +1,23 @@
 Test project .*/Tests/RunCMake/GoogleTest/GoogleTest-discovery-arg-change
-  Test #[0-9]+: typed\.case<short>
-  Test #[0-9]+: typed\.case<float>
-  Test #[0-9]+: typed\.case<char>
-  Test #[0-9]+: ns\.typed\.case<short>
-  Test #[0-9]+: ns\.typed\.case<float>
-  Test #[0-9]+: ns\.typed\.case<char>
-  Test #[0-9]+: prefix/typed\.case<short>
-  Test #[0-9]+: prefix/typed\.case<float>
-  Test #[0-9]+: prefix/typed\.case<char>
+  Test +#[0-9]+: typed\.case<short>
+  Test +#[0-9]+: typed\.case<float>
+  Test +#[0-9]+: typed\.case<char>
+  Test +#[0-9]+: typed\.case<int>
+  Test +#[0-9]+: ns\.typed\.case<short>
+  Test +#[0-9]+: ns\.typed\.case<float>
+  Test +#[0-9]+: ns\.typed\.case<char>
+  Test +#[0-9]+: ns\.typed\.case<int>
+  Test +#[0-9]+: prefix/typed\.case<short>
+  Test +#[0-9]+: prefix/typed\.case<float>
+  Test +#[0-9]+: prefix/typed\.case<char>
+  Test +#[0-9]+: prefix/typed\.case<int>
+  Test +#[0-9]+: both_suite\.test/VALUE<TYPE>
+  Test +#[0-9]+: both_suite\.case/VALUE<TYPE>
+  Test +#[0-9]+: both\.test/VALUE<TYPE>
+  Test +#[0-9]+: both\.case/VALUE<TYPE>
+  Test +#[0-9]+: ns\.both\.test/VALUE<TYPE>
+  Test +#[0-9]+: ns\.both\.case/VALUE<TYPE>
+  Test +#[0-9]+: prefix/both\.test/VALUE<TYPE>
+  Test +#[0-9]+: prefix/both\.case/VALUE<TYPE>
 
 Total Tests: [0-9]+
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test1-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test1-stdout.txt
index 4fa2b5c..a70ea9b 100644
--- a/Tests/RunCMake/GoogleTest/GoogleTest-test1-stdout.txt
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-test1-stdout.txt
@@ -25,30 +25,42 @@
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<float>!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:typed\.case<char>!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<char>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:typed\.case<int>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<int>!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<short>!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<short>!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<float>!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<float>!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<char>!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<char>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.typed\.case<int>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<int>!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<short>!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<short>!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<float>!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<float>!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<char>!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<char>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/typed\.case<int>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<int>!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:value/test\.case/1!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/1!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:value/test\.case/"foo"!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/"foo"!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:value/test\.case/'c'!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/'c'!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.value/test\.case/1!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/1!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.value/test\.case/"foo"!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/"foo"!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.value/test\.case/'c'!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/'c'!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/value/test\.case/1!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/1!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/value/test\.case/"foo"!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/"foo"!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/value/test\.case/'c'!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/'c'!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:param/special\.case/"semicolon;"!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"semicolon;"!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:param/special\.case/"backslash\\"!1
@@ -97,6 +109,22 @@
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/"__csb___text"!1 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/param/special\.case/"S o m  e   "!1
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/"S o m  e   "!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.test/VALUE<TYPE>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.test/VALUE<TYPE>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.case/VALUE<TYPE>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.case/VALUE<TYPE>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.test/VALUE<TYPE>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.test/VALUE<TYPE>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.case/VALUE<TYPE>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.case/VALUE<TYPE>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.test/VALUE<TYPE>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.test/VALUE<TYPE>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.case/VALUE<TYPE>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.case/VALUE<TYPE>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.test/VALUE<TYPE>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.test/VALUE<TYPE>!1 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.case/VALUE<TYPE>!1
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.case/VALUE<TYPE>!1 \.+ +Passed +[0-9.]+ sec
 
 100% tests passed, 0 tests failed out of [0-9]+
 
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test2-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test2-stdout.txt
index 99b641b..5ae246c 100644
--- a/Tests/RunCMake/GoogleTest/GoogleTest-test2-stdout.txt
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-test2-stdout.txt
@@ -25,30 +25,42 @@
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<float>!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:typed\.case<char>!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<char>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:typed\.case<int>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<int>!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<short>!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<short>!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<float>!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<float>!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<char>!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<char>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.typed\.case<int>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<int>!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<short>!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<short>!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<float>!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<float>!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<char>!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<char>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/typed\.case<int>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<int>!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:value/test\.case/1!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/1!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:value/test\.case/"foo"!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/"foo"!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:value/test\.case/'c'!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/'c'!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.value/test\.case/1!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/1!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.value/test\.case/"foo"!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/"foo"!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.value/test\.case/'c'!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/'c'!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/value/test\.case/1!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/1!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/value/test\.case/"foo"!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/"foo"!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/value/test\.case/'c'!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/'c'!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:param/special\.case/"semicolon;"!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/"semicolon;"!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:param/special\.case/"backslash\\"!2
@@ -97,6 +109,22 @@
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/"__csb___text"!2 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/param/special\.case/"S o m  e   "!2
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/"S o m  e   "!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.test/VALUE<TYPE>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.test/VALUE<TYPE>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.case/VALUE<TYPE>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.case/VALUE<TYPE>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.test/VALUE<TYPE>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.test/VALUE<TYPE>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.case/VALUE<TYPE>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.case/VALUE<TYPE>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.test/VALUE<TYPE>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.test/VALUE<TYPE>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.case/VALUE<TYPE>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.case/VALUE<TYPE>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.test/VALUE<TYPE>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.test/VALUE<TYPE>!2 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.case/VALUE<TYPE>!2
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.case/VALUE<TYPE>!2 \.+ +Passed +[0-9.]+ sec
 
 100% tests passed, 0 tests failed out of [0-9]+
 
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test4-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test4-stdout.txt
index d9203bc..671cdfb 100644
--- a/Tests/RunCMake/GoogleTest/GoogleTest-test4-stdout.txt
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-test4-stdout.txt
@@ -5,18 +5,40 @@
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<float>!4 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:typed\.case<char>!4
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<char>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:typed\.case<int>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<int>!4 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<short>!4
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<short>!4 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<float>!4
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<float>!4 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:ns\.typed\.case<char>!4
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<char>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.typed\.case<int>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<int>!4 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<short>!4
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<short>!4 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<float>!4
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<float>!4 \.+ +Passed +[0-9.]+ sec
  *Start +[0-9]+: TEST:prefix/typed\.case<char>!4
  *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<char>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/typed\.case<int>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<int>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.test/VALUE<TYPE>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.test/VALUE<TYPE>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.case/VALUE<TYPE>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.case/VALUE<TYPE>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.test/VALUE<TYPE>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.test/VALUE<TYPE>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.case/VALUE<TYPE>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.case/VALUE<TYPE>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.test/VALUE<TYPE>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.test/VALUE<TYPE>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.case/VALUE<TYPE>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.case/VALUE<TYPE>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.test/VALUE<TYPE>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.test/VALUE<TYPE>!4 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.case/VALUE<TYPE>!4
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.case/VALUE<TYPE>!4 \.+ +Passed +[0-9.]+ sec
 
 100% tests passed, 0 tests failed out of [0-9]+
 
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test5-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test5-stdout.txt
new file mode 100644
index 0000000..805ec9e
--- /dev/null
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-test5-stdout.txt
@@ -0,0 +1,87 @@
+Test project .*
+ *Start +[0-9]+: TEST:value/test\.case/0!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/0!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:value/test\.case/1!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/1!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:value/test\.case/named!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:value/test\.case/named!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.value/test\.case/0!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/0!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.value/test\.case/1!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/1!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.value/test\.case/named!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.value/test\.case/named!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/value/test\.case/0!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/0!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/value/test\.case/1!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/1!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/value/test\.case/named!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/value/test\.case/named!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:param/special\.case/0!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/0!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:param/special\.case/1!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/1!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:param/special\.case/2!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/2!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:param/special\.case/3!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/3!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:param/special\.case/4!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/4!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:param/special\.case/5!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/5!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:param/special\.case/6!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/6!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:param/special\.case/7!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:param/special\.case/7!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.param/special\.case/0!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/0!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.param/special\.case/1!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/1!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.param/special\.case/2!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/2!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.param/special\.case/3!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/3!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.param/special\.case/4!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/4!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.param/special\.case/5!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/5!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.param/special\.case/6!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/6!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.param/special\.case/7!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.param/special\.case/7!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/param/special\.case/0!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/0!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/param/special\.case/1!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/1!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/param/special\.case/2!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/2!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/param/special\.case/3!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/3!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/param/special\.case/4!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/4!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/param/special\.case/5!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/5!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/param/special\.case/6!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/6!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/param/special\.case/7!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/param/special\.case/7!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.test<TYPE>!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.test<TYPE>!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.case/test<TYPE>!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.case/test<TYPE>!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.test<TYPE>!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.test<TYPE>!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.case/test<TYPE>!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.case/test<TYPE>!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.test<TYPE>!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.test<TYPE>!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.case/test<TYPE>!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.case/test<TYPE>!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.test<TYPE>!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.test<TYPE>!5 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.case/test<TYPE>!5
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.case/test<TYPE>!5 \.+ +Passed +[0-9.]+ sec
+
+100% tests passed, 0 tests failed out of [0-9]+
+
+Total Test time \(real\) = +[0-9.]+ sec
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test6-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test6-stdout.txt
new file mode 100644
index 0000000..d467bbc
--- /dev/null
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-test6-stdout.txt
@@ -0,0 +1,45 @@
+Test project .*
+ *Start +[0-9]+: TEST:typed\.case<0>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<0>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:typed\.case<1>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<1>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:typed\.case<42>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed\.case<42>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:typed.case<named>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:typed.case<named>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.typed\.case<0>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<0>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.typed\.case<1>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<1>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.typed\.case<42>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed\.case<42>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.typed.case<named>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.typed.case<named>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/typed\.case<0>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<0>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/typed\.case<1>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<1>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/typed\.case<42>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed\.case<42>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/typed.case<named>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/typed.case<named>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.test/VALUE!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.test/VALUE!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.case/VALUE!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.case/VALUE!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.test/VALUE<suite>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.test/VALUE<suite>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.case/VALUE<suite>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.case/VALUE<suite>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.test/VALUE<suite>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.test/VALUE<suite>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.case/VALUE<suite>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.case/VALUE<suite>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.test/VALUE<suite>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.test/VALUE<suite>!6 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.case/VALUE<suite>!6
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.case/VALUE<suite>!6 \.+ +Passed +[0-9.]+ sec
+
+100% tests passed, 0 tests failed out of [0-9]+
+
+Total Test time \(real\) = +[0-9.]+ sec
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest-test7-stdout.txt b/Tests/RunCMake/GoogleTest/GoogleTest-test7-stdout.txt
new file mode 100644
index 0000000..13ee9d0
--- /dev/null
+++ b/Tests/RunCMake/GoogleTest/GoogleTest-test7-stdout.txt
@@ -0,0 +1,21 @@
+Test project .*
+ *Start +[0-9]+: TEST:both_suite\.test!7
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.test!7 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both_suite\.case/test!7
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both_suite\.case/test!7 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.test<suite>!7
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.test<suite>!7 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:both\.case/test<suite>!7
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:both\.case/test<suite>!7 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.test<suite>!7
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.test<suite>!7 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:ns\.both\.case/test<suite>!7
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:ns\.both\.case/test<suite>!7 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.test<suite>!7
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.test<suite>!7 \.+ +Passed +[0-9.]+ sec
+ *Start +[0-9]+: TEST:prefix/both\.case/test<suite>!7
+ *[0-9]+/[0-9]+ +Test +#[0-9]+: TEST:prefix/both\.case/test<suite>!7 \.+ +Passed +[0-9.]+ sec
+
+100% tests passed, 0 tests failed out of [0-9]+
+
+Total Test time \(real\) = +[0-9.]+ sec
diff --git a/Tests/RunCMake/GoogleTest/GoogleTest.cmake b/Tests/RunCMake/GoogleTest/GoogleTest.cmake
index 2ed43fc..e55967a 100644
--- a/Tests/RunCMake/GoogleTest/GoogleTest.cmake
+++ b/Tests/RunCMake/GoogleTest/GoogleTest.cmake
@@ -42,6 +42,37 @@
   PROPERTIES LABELS TEST4
 )
 
+gtest_discover_tests(
+  fake_gtest
+  TEST_PREFIX TEST:
+  TEST_SUFFIX !5
+  TEST_FILTER value*
+  EXTRA_ARGS how now "\"brown\" cow"
+  PROPERTIES LABELS TEST5
+  NO_PRETTY_VALUES
+)
+
+gtest_discover_tests(
+  fake_gtest
+  TEST_PREFIX TEST:
+  TEST_SUFFIX !6
+  TEST_FILTER typed*
+  EXTRA_ARGS how now "\"brown\" cow"
+  PROPERTIES LABELS TEST6
+  NO_PRETTY_TYPES
+)
+
+gtest_discover_tests(
+  fake_gtest
+  TEST_PREFIX TEST:
+  TEST_SUFFIX !7
+  TEST_FILTER dynamic*
+  EXTRA_ARGS how now "\"brown\" cow"
+  PROPERTIES LABELS TEST7
+  NO_PRETTY_VALUES
+  NO_PRETTY_TYPES
+)
+
 add_executable(no_tests_defined no_tests_defined.cpp)
 xcode_sign_adhoc(no_tests_defined)
 
diff --git a/Tests/RunCMake/GoogleTest/GoogleTestDefSourceLine.cmake b/Tests/RunCMake/GoogleTest/GoogleTestDefSourceLine.cmake
new file mode 100644
index 0000000..19e41c0
--- /dev/null
+++ b/Tests/RunCMake/GoogleTest/GoogleTestDefSourceLine.cmake
@@ -0,0 +1,11 @@
+enable_language(CXX)
+include(GoogleTest)
+
+enable_testing()
+
+include(xcode_sign_adhoc.cmake)
+
+add_executable(fake_gtest fake_gtest.cpp)
+xcode_sign_adhoc(fake_gtest)
+
+gtest_discover_tests(fake_gtest)
diff --git a/Tests/RunCMake/GoogleTest/GoogleTestLegacyParser.cmake b/Tests/RunCMake/GoogleTest/GoogleTestLegacyParser.cmake
new file mode 100644
index 0000000..10451a8
--- /dev/null
+++ b/Tests/RunCMake/GoogleTest/GoogleTestLegacyParser.cmake
@@ -0,0 +1,16 @@
+enable_language(CXX)
+include(GoogleTest)
+
+enable_testing()
+
+include(xcode_sign_adhoc.cmake)
+
+add_executable(fake_gtest fake_gtest.cpp)
+xcode_sign_adhoc(fake_gtest)
+
+gtest_discover_tests(
+  fake_gtest
+  TEST_PREFIX TEST:
+  TEST_SUFFIX !1
+  EXTRA_ARGS how now "\"brown\" cow"
+)
diff --git a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
index f50cae7..122a409 100644
--- a/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GoogleTest/RunCMakeTest.cmake
@@ -65,6 +65,27 @@
     --no-label-summary
   )
 
+  run_cmake_command(GoogleTest-test5
+    ${CMAKE_CTEST_COMMAND}
+    -C Debug
+    -L TEST5
+    --no-label-summary
+  )
+
+  run_cmake_command(GoogleTest-test6
+    ${CMAKE_CTEST_COMMAND}
+    -C Debug
+    -L TEST6
+    --no-label-summary
+  )
+
+  run_cmake_command(GoogleTest-test7
+    ${CMAKE_CTEST_COMMAND}
+    -C Debug
+    -L TEST7
+    --no-label-summary
+  )
+
   run_cmake_command(GoogleTest-test-missing
     ${CMAKE_CTEST_COMMAND}
     -C Debug
@@ -381,6 +402,63 @@
   )
 endfunction()
 
+function(run_GoogleTest_LegacyParser)
+  # Use a single build tree for a few tests without cleaning.
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTestLegacyParser-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+  endif()
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  set(ENV{NO_GTEST_JSON_OUTPUT} 1)
+
+  run_cmake(GoogleTestLegacyParser)
+
+  run_cmake_command(GoogleTestLegacyParser-build
+    ${CMAKE_COMMAND}
+    --build .
+    --config Debug
+    --target fake_gtest
+  )
+
+  set(RunCMake-stdout-file GoogleTest-test1-stdout.txt)
+  run_cmake_command(GoogleTestLegacyParser-test
+    ${CMAKE_CTEST_COMMAND}
+    -C Debug
+    --no-label-summary
+  )
+
+  unset(ENV{NO_GTEST_JSON_OUTPUT})
+endfunction()
+
+function(run_GoogleTest_DEF_SOURCE_LINE)
+  # Use a single build tree for a few tests without cleaning.
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/GoogleTest-DEF_SOURCE_LINE-build)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+    set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+  endif()
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  run_cmake(GoogleTestDefSourceLine)
+
+  run_cmake_command(GoogleTest-DEF_SOURCE_LINE-build
+    ${CMAKE_COMMAND}
+    --build .
+    --config Debug
+    --target fake_gtest
+  )
+  run_cmake_command(GoogleTest-DEF_SOURCE_LINE
+    ${CMAKE_CTEST_COMMAND}
+    -C Debug
+    -R "^basic\\.case_"
+    --show-only=json-v1
+  )
+endfunction()
+
 foreach(DISCOVERY_MODE POST_BUILD PRE_TEST)
   message(STATUS "Testing ${DISCOVERY_MODE} discovery mode via CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE global override...")
   run_GoogleTest(${DISCOVERY_MODE})
@@ -428,3 +506,6 @@
     --output-on-failure
   )
 endblock()
+
+run_GoogleTest_LegacyParser()
+run_GoogleTest_DEF_SOURCE_LINE()
diff --git a/Tests/RunCMake/GoogleTest/WorkDirWithSpaces.cmake b/Tests/RunCMake/GoogleTest/WorkDirWithSpaces.cmake
index 53b0dd5..f39ecf3 100644
--- a/Tests/RunCMake/GoogleTest/WorkDirWithSpaces.cmake
+++ b/Tests/RunCMake/GoogleTest/WorkDirWithSpaces.cmake
@@ -14,6 +14,22 @@
   test1
   test2
 ]=])
+file(WRITE ${workdir}/test_list_output.json [=[
+{
+    "tests": 2,
+    "name": "AllTests",
+    "testsuites": [
+        {
+            "name": "WorkDirWithSpaces",
+            "tests": 2,
+            "testsuite": [
+                { "name": "test1", "file": "file.cpp", "line": 42 },
+                { "name": "test2", "file": "file.cpp", "line": 43 }
+            ]
+        }
+    ]
+}
+]=])
 file(WRITE ${workdir}/test_output.txt [=[
 Some output text for the test.
 ]=])
diff --git a/Tests/RunCMake/GoogleTest/configuration_gtest.cpp b/Tests/RunCMake/GoogleTest/configuration_gtest.cpp
index 3cbb134..930f2d4 100644
--- a/Tests/RunCMake/GoogleTest/configuration_gtest.cpp
+++ b/Tests/RunCMake/GoogleTest/configuration_gtest.cpp
@@ -1,3 +1,5 @@
+#include <cstdlib>
+#include <fstream>
 #include <iostream>
 #include <string>
 
@@ -7,15 +9,49 @@
   // it only requires that we produces output in the expected format when
   // invoked with --gtest_list_tests. Thus, we fake that here. This allows us
   // to test the module without actually needing Google Test.
-  if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests") {
+  if (argc > 2 && std::string(argv[1]) == "--gtest_list_tests" &&
+      std::string(argv[2]).find("--gtest_output=json:") != std::string::npos) {
     std::cout << "configuration." << std::endl;
 #ifdef DEBUG
     std::cout << "  DISABLED_case_release" << std::endl;
     std::cout << "  case_debug" << std::endl;
+    std::string release_name("DISABLED_case_release");
+    std::string debug_name("case_debug");
 #else
     std::cout << "  case_release" << std::endl;
     std::cout << "  DISABLED_case_debug" << std::endl;
+    std::string release_name("case_release");
+    std::string debug_name("DISABLED_case_debug");
 #endif
+
+    std::string output_param(argv[2]);
+    std::string::size_type split = output_param.find(":");
+    std::string filepath = output_param.substr(split + 1);
+    // The full file path is passed
+    std::ofstream ostrm(filepath.c_str(), std::ios::binary);
+    if (!ostrm) {
+      std::cerr << "Failed to create file: " << filepath.c_str() << std::endl;
+      return 1;
+    }
+
+    ostrm << "{\n"
+             "    \"tests\": 2,\n"
+             "    \"name\": \"AllTests\",\n"
+             "    \"testsuites\": [\n"
+             "        {\n"
+             "            \"name\": \"configuration\",\n"
+             "            \"tests\": 2,\n"
+             "            \"testsuite\": [\n"
+             "                { \"name\": \""
+          << release_name
+          << "\", \"file\": \"file.cpp\", \"line\": 42 },\n"
+             "                { \"name\": \""
+          << debug_name
+          << "\", \"file\": \"file.cpp\", \"line\": 43 }\n"
+             "            ]\n"
+             "        }\n"
+             "    ]\n"
+             "}";
     return 0;
   }
 
diff --git a/Tests/RunCMake/GoogleTest/fake_gtest.cpp b/Tests/RunCMake/GoogleTest/fake_gtest.cpp
index c612b24..f034d1a 100644
--- a/Tests/RunCMake/GoogleTest/fake_gtest.cpp
+++ b/Tests/RunCMake/GoogleTest/fake_gtest.cpp
@@ -1,6 +1,16 @@
+#define _CRT_SECURE_NO_WARNINGS // work around 'getenv' deprecation on WIN32
+
+#include <cstdlib>
+#include <fstream>
 #include <iostream>
 #include <string>
 
+#if defined(_MSC_VER) && _MSC_VER < 1310
+#  define GETENV ::getenv
+#else
+#  define GETENV std::getenv
+#endif
+
 #define ARRAY_SIZE(a) sizeof(a) / sizeof(*a)
 
 int main(int argc, char** argv)
@@ -10,30 +20,100 @@
   // invoked with --gtest_list_tests. Thus, we fake that here. This allows us
   // to test the module without actually needing Google Test.
   bool is_filtered =
-    argc > 2 && std::string(argv[2]).find("--gtest_filter=") == 0;
-  bool is_basic_only =
-    is_filtered && std::string(argv[2]).find("basic*") != std::string::npos;
-  bool is_typed_only =
-    is_filtered && std::string(argv[2]).find("typed*") != std::string::npos;
+    argc > 3 && std::string(argv[3]).find("--gtest_filter=") == 0;
+  bool add_basic_tests =
+    !is_filtered || (std::string(argv[3]).find("basic*") != std::string::npos);
+  bool add_typed_tests =
+    !is_filtered || (std::string(argv[3]).find("typed*") != std::string::npos);
+  bool add_value_tests =
+    !is_filtered || (std::string(argv[3]).find("value*") != std::string::npos);
+  bool add_dynamic_tests = !is_filtered ||
+    (std::string(argv[3]).find("dynamic*") != std::string::npos);
 
-  if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests") {
-    if (!is_typed_only) {
-      char const* basic_suite_names[] = { "basic.", "ns.basic." };
+  if (argc > 2 && std::string(argv[1]) == "--gtest_list_tests" &&
+      std::string(argv[2]).find("--gtest_output=json:") != std::string::npos) {
+    std::ofstream ostrm;
+    if (!GETENV("NO_GTEST_JSON_OUTPUT")) {
+      std::string output_param(argv[2]);
+      std::string::size_type split = output_param.find(":");
+      std::string filepath = output_param.substr(split + 1);
+      // The full file path is passed
+      ostrm.open(filepath.c_str(), std::ios::out | std::ios::binary);
+      if (!ostrm) {
+        std::cerr << "Failed to create file: " << filepath.c_str()
+                  << std::endl;
+        return 1;
+      }
+    } else {
+      std::cout << "WARNING: An old-style warning." << std::endl;
+      std::cout << "[ WARNING ] A new-style warning." << std::endl;
+      std::cout << "[  ERROR  ] A new-style error." << std::endl;
+    }
+
+    int tests = 0;
+    ostrm << "{\n"
+             "    \"name\": \"AllTests\",\n"
+             "    \"testsuites\": [";
+
+    if (add_basic_tests) {
+      char const* basic_suite_names[] = { "basic", "ns.basic" };
       for (size_t i = 0; i < ARRAY_SIZE(basic_suite_names); i++) {
-        std::cout << basic_suite_names[i] << std::endl;
+        std::cout << basic_suite_names[i] << '.' << std::endl;
         std::cout << "  case_foo" << std::endl;
         std::cout << "  case_bar" << std::endl;
         std::cout << "  DISABLED_disabled_case" << std::endl;
         std::cout << "  DISABLEDnot_really_case" << std::endl;
+
+        if (tests)
+          ostrm << ",";
+        ostrm << "\n"
+                 "        {\n"
+                 "            \"name\": \""
+              << basic_suite_names[i]
+              << "\",\n"
+                 "            \"tests\": 4,\n"
+                 "            \"testsuite\": [\n"
+                 "                { \"name\": \"case_foo\", \"file\": "
+                 "\"file1.cpp\", \"line\": 1 },\n"
+                 "                { \"name\": \"case_bar\", \"file\": "
+                 "\"file with spaces.cpp\", \"line\": 2 },\n"
+                 "                { \"name\": \"DISABLED_disabled_case\", "
+                 "\"file\": \"file1.cpp\", \"line\": 3 },\n"
+                 "                { \"name\": \"DISABLEDnot_really_case\", "
+                 "\"file\": \"file1.cpp\", \"line\": 4 }\n"
+                 "            ]\n"
+                 "        }";
+        tests += 4;
       }
     }
-    if (!is_basic_only && !is_typed_only) {
+    if (!is_filtered) {
       std::cout << "DISABLED_disabled." << std::endl;
       std::cout << "  case" << std::endl;
       std::cout << "DISABLEDnotreally." << std::endl;
       std::cout << "  case" << std::endl;
+
+      if (tests)
+        ostrm << ",";
+      ostrm << "\n"
+               "        {\n"
+               "            \"name\": \"DISABLED_disabled\",\n"
+               "            \"tests\": 1,\n"
+               "            \"testsuite\": [\n"
+               "                { \"name\": \"case\", \"file\": "
+               "\"file2.cpp\", \"line\": 1 }\n"
+               "            ]\n"
+               "        },\n"
+               "        {\n"
+               "            \"name\": \"DISABLEDnotreally\",\n"
+               "            \"tests\": 1,\n"
+               "            \"testsuite\": [\n"
+               "                { \"name\": \"case\", \"file\": "
+               "\"file2.cpp\", \"line\": 2 }\n"
+               "            ]\n"
+               "        }";
+      tests += 2;
     }
-    if (!is_basic_only) {
+    if (add_typed_tests) {
       char const* typed_suite_names[] = { "typed", "ns.typed",
                                           "prefix/typed" };
       for (size_t i = 0; i < ARRAY_SIZE(typed_suite_names); i++) {
@@ -43,15 +123,75 @@
         std::cout << "  case" << std::endl;
         std::cout << typed_suite_names[i] << "/42.  # TypeParam = char\n";
         std::cout << "  case" << std::endl;
+        std::cout << typed_suite_names[i] << "/named.  # TypeParam = int\n";
+        std::cout << "  case" << std::endl;
+
+        if (tests)
+          ostrm << ",";
+        ostrm << "\n"
+                 "        {\n"
+                 "            \"name\": \""
+              << typed_suite_names[i]
+              << "/0\",\n"
+                 "            \"tests\": 1, \"testsuite\": [ { \"name\": "
+                 "\"case\", \"type_param\": \"short\", \"file\": "
+                 "\"file3.cpp\", \"line\": 1 } ]\n"
+                 "        },\n"
+                 "        {\n"
+                 "            \"name\": \""
+              << typed_suite_names[i]
+              << "/1\",\n"
+                 "            \"tests\": 1, \"testsuite\": [ { \"name\": "
+                 "\"case\", \"type_param\": \"float\", \"file\": "
+                 "\"file3.cpp\", \"line\": 2 } ]\n"
+                 "        },\n"
+                 "        {\n"
+                 "            \"name\": \""
+              << typed_suite_names[i]
+              << "/42\",\n"
+                 "            \"tests\": 1, \"testsuite\": [ { \"name\": "
+                 "\"case\", \"type_param\": \"char\", \"file\": "
+                 "\"file3.cpp\", \"line\": 3 } ]\n"
+                 "        },\n"
+                 "        {\n"
+                 "            \"name\": \""
+              << typed_suite_names[i]
+              << "/named\",\n"
+                 "            \"tests\": 1, \"testsuite\": [ { \"name\": "
+                 "\"case\", \"type_param\": \"int\", \"file\": \"file3.cpp\", "
+                 "\"line\": 4 } ]\n"
+                 "        }";
+        tests += 4;
       }
     }
-    if (!is_basic_only && !is_typed_only) {
+    if (add_value_tests) {
       char const* value_suite_names[] = { "value", "ns.value",
                                           "prefix/value" };
       for (size_t i = 0; i < ARRAY_SIZE(value_suite_names); i++) {
         std::cout << value_suite_names[i] << "/test." << std::endl;
         std::cout << "  case/0  # GetParam() = 1" << std::endl;
         std::cout << "  case/1  # GetParam() = \"foo\"" << std::endl;
+        std::cout << "  case/named  # GetParam() = 'c'" << std::endl;
+
+        if (tests)
+          ostrm << ",";
+        ostrm
+          << "\n"
+             "        {\n"
+             "            \"name\": \""
+          << value_suite_names[i] << "/test"
+          << "\",\n"
+             "            \"tests\": 3,\n"
+             "            \"testsuite\": [\n"
+             "                { \"name\": \"case/0\", \"value_param\": \"1\", "
+             "\"file\": \"file4.cpp\", \"line\": 1 },\n"
+             "                { \"name\": \"case/1\", \"value_param\": "
+             "\"\\\"foo\\\"\", \"file\": \"file4.cpp\", \"line\": 2 },\n"
+             "                { \"name\": \"case/named\", \"value_param\": "
+             "\"'c'\", \"file\": \"file4.cpp\", \"line\": 3 }\n"
+             "            ]\n"
+             "        }";
+        tests += 3;
       }
       char const* param_suite_names[] = { "param", "ns.param",
                                           "prefix/param" };
@@ -65,8 +205,74 @@
         std::cout << "  case/5  # GetParam() = \"__osbtext\"" << std::endl;
         std::cout << "  case/6  # GetParam() = \"__csb___text\"" << std::endl;
         std::cout << "  case/7  # GetParam() = \"S o m  e   \"" << std::endl;
+
+        ostrm
+          << ",\n"
+             "        {\n"
+             "            \"name\": \""
+          << param_suite_names[j] << "/special"
+          << "\",\n"
+             "            \"tests\": 8,\n"
+             "            \"testsuite\": [\n"
+             "                { \"name\": \"case/0\", \"value_param\": "
+             "\"\\\"semicolon;\\\"\", \"file\": \"file4.cpp\", \"line\": 1 "
+             "},\n"
+             "                { \"name\": \"case/1\", \"value_param\": "
+             "\"\\\"backslash\\\\\\\"\", \"file\": \"file4.cpp\", \"line\": 2 "
+             "},\n"
+             "                { \"name\": \"case/2\", \"value_param\": "
+             "\"\\\"${var}\\\"\", \"file\": \"file4.cpp\", \"line\": 3 },\n"
+             "                { \"name\": \"case/3\", \"value_param\": "
+             "\"'['\", \"file\": \"file4.cpp\", \"line\": 4 },\n"
+             "                { \"name\": \"case/4\", \"value_param\": "
+             "\"\\\"]]=]\\\"\", \"file\": \"file4.cpp\", \"line\": 5 },\n"
+             "                { \"name\": \"case/5\", \"value_param\": "
+             "\"\\\"__osbtext\\\"\", \"file\": \"file4.cpp\", \"line\": 5 },\n"
+             "                { \"name\": \"case/6\", \"value_param\": "
+             "\"\\\"__csb___text\\\"\", \"file\": \"file4.cpp\", \"line\": 5 "
+             "},\n"
+             "                { \"name\": \"case/7\", \"value_param\": "
+             "\"\\\"S o m  e   \\\"\", \"file\": \"file4.cpp\", \"line\": 6 "
+             "}\n"
+             "            ]\n"
+             "        }";
+        tests += 8;
       }
     }
+    if (add_value_tests || add_typed_tests || add_dynamic_tests) {
+      char const* both_suite_names[] = { "both_suite", "both/suite",
+                                         "ns.both/suite",
+                                         "prefix/both/suite" };
+      for (size_t k = 0; k < ARRAY_SIZE(both_suite_names); k++) {
+        std::cout << both_suite_names[k] << ".  # TypeParam = TYPE"
+                  << std::endl;
+        std::cout << "  test  # GetParam() = VALUE" << std::endl;
+        std::cout << "  case/test  # GetParam() = VALUE" << std::endl;
+
+        if (tests)
+          ostrm << ",";
+        ostrm << "\n"
+                 "          {\n"
+                 "              \"name\": \""
+              << both_suite_names[k]
+              << "\",\n"
+                 "              \"tests\": 1,\n"
+                 "              \"testsuite\": [\n"
+                 "                  { \"name\": \"test\", \"type_param\": "
+                 "\"TYPE\", \"value_param\": \"VALUE\", \"file\": "
+                 "\"file5.cpp\", \"line\": 1 },\n"
+                 "                  { \"name\": \"case/test\", "
+                 "\"type_param\": \"TYPE\", \"value_param\": \"VALUE\", "
+                 "\"file\": \"file5.cpp\", \"line\": 2 }\n"
+                 "              ]\n"
+                 "          }";
+        tests += 2;
+      }
+    }
+    ostrm << "\n"
+             "    ],\n"
+             "    \"tests\": "
+          << tests << "\n}";
     return 0;
   }
 
diff --git a/Tests/RunCMake/GoogleTest/flush_script_test.cpp b/Tests/RunCMake/GoogleTest/flush_script_test.cpp
index 60270bd..a1f419e 100644
--- a/Tests/RunCMake/GoogleTest/flush_script_test.cpp
+++ b/Tests/RunCMake/GoogleTest/flush_script_test.cpp
@@ -1,3 +1,4 @@
+#include <fstream>
 #include <iostream>
 #include <string>
 
@@ -7,14 +8,52 @@
   // it only requires that we produces output in the expected format when
   // invoked with --gtest_list_tests. Thus, we fake that here. This allows us
   // to test the module without actually needing Google Test.
-  if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests") {
+  if (argc > 2 && std::string(argv[1]) == "--gtest_list_tests" &&
+      std::string(argv[2]).find("--gtest_output=json:") != std::string::npos) {
     std::cout << "flush_script_test.\n";
+
+    std::string output_param(argv[2]);
+    std::string::size_type split = output_param.find(":");
+    std::string filepath = output_param.substr(split + 1);
+    // The full file path is passed
+    std::ofstream ostrm(filepath.c_str(), std::ios::binary);
+    if (!ostrm) {
+      std::cerr << "Failed to create file: " << filepath.c_str() << std::endl;
+      return 1;
+    }
+
     size_t const flushThreshold = 50000;
     size_t const flushAfter = 4;
     size_t const testCaseNum = 3 * flushAfter;
+    ostrm << "{\n"
+             "    \"tests\": 4,\n"
+             "    \"name\": \"AllTests\",\n"
+             "    \"testsuites\": [\n"
+             "        {\n"
+             "            \"name\": \"flush_script_test\",\n"
+             "            \"tests\": 12,\n"
+             "            \"testsuite\": [";
+
     std::string testName(flushThreshold / flushAfter, 'T');
-    for (size_t i = 1; i <= testCaseNum; ++i)
+    for (size_t i = 1; i <= testCaseNum; ++i) {
       std::cout << "  t" << i << testName.c_str() << "\n";
+      if (i != 1)
+        ostrm << ",";
+      ostrm << "\n"
+               "                {\n"
+               "                  \"name\": \"t"
+            << i << testName.c_str()
+            << "\",\n"
+               "                  \"file\": \"file2.cpp\",\n"
+               "                  \"line\": 47\n"
+               "                }";
+    }
+    ostrm << "\n"
+             "            ]\n"
+             "        }\n"
+             "    ]\n"
+             "}";
   }
+
   return 0;
 }
diff --git a/Tests/RunCMake/GoogleTest/launcher_test.c b/Tests/RunCMake/GoogleTest/launcher_test.c
index eed6206..c7ef8a4 100644
--- a/Tests/RunCMake/GoogleTest/launcher_test.c
+++ b/Tests/RunCMake/GoogleTest/launcher_test.c
@@ -8,15 +8,46 @@
 }
 */
 
+char const gtest_output_json_flag_prefix[] = "--gtest_output=json:";
+char const json_output[] = "{\n"
+                           "    \"tests\": 1,\n"
+                           "    \"name\": \"AllTests\",\n"
+                           "    \"testsuites\": [\n"
+                           "        {\n"
+                           "            \"name\": \"launcher_test\",\n"
+                           "            \"tests\": 1,\n"
+                           "            \"testsuite\": [\n"
+                           "                { \"name\": \"test1\", \"file\": "
+                           "\"file.cpp\", \"line\": 42 }\n"
+                           "            ]\n"
+                           "        }\n"
+                           "    ]\n"
+                           "}";
+
 int main(int argc, char** argv)
 {
   /* Note: Launcher.cmake doesn't actually depend on Google Test as such;
    * it only requires that we produces output in the expected format when
    * invoked with --gtest_list_tests. Thus, we fake that here. This allows us
    * to test the module without actually needing Google Test.  */
-  if (argc > 1 && strcmp(argv[1], "--gtest_list_tests") == 0) {
+  char* filepath;
+  FILE* ofile;
+
+  if (argc > 2 && strcmp(argv[1], "--gtest_list_tests") == 0 &&
+      strncmp(argv[2], gtest_output_json_flag_prefix,
+              strlen(gtest_output_json_flag_prefix)) == 0) {
     printf("launcher_test.\n");
     printf("  test1\n");
+    filepath = strchr(argv[2], ':') + 1;
+    /* The full file path is passed */
+    ofile = fopen(filepath, "wb");
+
+    if (!ofile) {
+      fprintf(stderr, "Failed to create file: %s\n", filepath);
+      return 1;
+    }
+    fprintf(ofile, "%s", json_output);
+    fclose(ofile);
   }
 
   printf("launcher_test.test1\n");
diff --git a/Tests/RunCMake/GoogleTest/skip_test.cpp b/Tests/RunCMake/GoogleTest/skip_test.cpp
index 919b1b3..be048ff 100644
--- a/Tests/RunCMake/GoogleTest/skip_test.cpp
+++ b/Tests/RunCMake/GoogleTest/skip_test.cpp
@@ -1,3 +1,4 @@
+#include <fstream>
 #include <iostream>
 #include <string>
 
@@ -14,9 +15,35 @@
   // it only requires that we produces output in the expected format when
   // invoked with --gtest_list_tests. Thus, we fake that here. This allows us
   // to test the module without actually needing Google Test.
-  if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests") {
+  if (argc > 2 && std::string(argv[1]) == "--gtest_list_tests" &&
+      std::string(argv[2]).find("--gtest_output=json:") != std::string::npos) {
     std::cout << "skip_test." << std::endl;
     std::cout << "  test1" << std::endl;
+
+    std::string output_param(argv[2]);
+    std::string::size_type split = output_param.find(":");
+    std::string filepath = output_param.substr(split + 1);
+    // The full file path is passed
+    std::ofstream ostrm(filepath.c_str(), std::ios::binary);
+    if (!ostrm) {
+      std::cerr << "Failed to create file: " << filepath.c_str() << std::endl;
+      return 1;
+    }
+    ostrm << "{\n"
+             "    \"tests\": 1,\n"
+             "    \"name\": \"AllTests\",\n"
+             "    \"testsuites\": [\n"
+             "        {\n"
+             "            \"name\": \"skip_test\",\n"
+             "            \"tests\": 1,\n"
+             "            \"testsuite\": [\n"
+             "                { \"name\": \"test1\", \"file\": \"file.cpp\", "
+             "\"line\": 42 }\n"
+             "            ]\n"
+             "        }\n"
+             "    ]\n"
+             "}";
+
     return 0;
   }
 
diff --git a/Tests/RunCMake/GoogleTest/test_list_extra_args.cpp b/Tests/RunCMake/GoogleTest/test_list_extra_args.cpp
index f63ec22..33e9a7b 100644
--- a/Tests/RunCMake/GoogleTest/test_list_extra_args.cpp
+++ b/Tests/RunCMake/GoogleTest/test_list_extra_args.cpp
@@ -1,3 +1,4 @@
+#include <fstream>
 #include <iostream>
 #include <string>
 
@@ -9,14 +10,45 @@
   // to test the module without actually needing Google Test.
 
   // Simple test of DISCOVERY_EXTRA_ARGS
-  if (argc > 4 && std::string(argv[1]) == "--gtest_list_tests" &&
-      std::string(argv[2]) == "how now" && std::string(argv[3]) == "" &&
-      std::string(argv[4]) == "\"brown\" cow") {
+  if (argc > 5 && std::string(argv[1]) == "--gtest_list_tests" &&
+      std::string(argv[2]).find("--gtest_output=json:") != std::string::npos &&
+      std::string(argv[3]) == "how now" && std::string(argv[4]) == "" &&
+      std::string(argv[5]) == "\"brown\" cow") {
     std::cout << "test_list_test/test.\n";
     std::cout << "  case/0  # GetParam() = 'one'\n";
     std::cout << "  case/1  # GetParam() = 'two'\n";
     std::cout << "  case/2  # GetParam() = 'three'\n";
     std::cout << "  case/3  # GetParam() = 'four'\n";
+
+    std::string output_param(argv[2]);
+    std::string::size_type split = output_param.find(":");
+    std::string filepath = output_param.substr(split + 1);
+    // The full file path is passed
+    std::ofstream ostrm(filepath.c_str(), std::ios::binary);
+    if (!ostrm) {
+      std::cerr << "Failed to create file: " << filepath.c_str() << std::endl;
+      return 1;
+    }
+    ostrm << "{\n"
+             "    \"tests\": 4,\n"
+             "    \"name\": \"AllTests\",\n"
+             "    \"testsuites\": [\n"
+             "        {\n"
+             "            \"name\": \"test_list_test/test\",\n"
+             "            \"tests\": 4,\n"
+             "            \"testsuite\": [\n"
+             "                { \"name\": \"case/0\", \"file\": \"file.cpp\", "
+             "\"line\": 42 },\n"
+             "                { \"name\": \"case/1\", \"file\": \"file.cpp\", "
+             "\"line\": 42 },\n"
+             "                { \"name\": \"case/2\", \"file\": \"file.cpp\", "
+             "\"line\": 42 },\n"
+             "                { \"name\": \"case/3\", \"file\": \"file.cpp\", "
+             "\"line\": 42 }\n"
+             "            ]\n"
+             "        }\n"
+             "    ]\n"
+             "}";
   }
   return 0;
 }
diff --git a/Tests/RunCMake/GoogleTest/test_list_test.cpp b/Tests/RunCMake/GoogleTest/test_list_test.cpp
index c9f9512..5a88797 100644
--- a/Tests/RunCMake/GoogleTest/test_list_test.cpp
+++ b/Tests/RunCMake/GoogleTest/test_list_test.cpp
@@ -1,3 +1,4 @@
+#include <fstream>
 #include <iostream>
 #include <string>
 
@@ -7,12 +8,44 @@
   // it only requires that we produces output in the expected format when
   // invoked with --gtest_list_tests. Thus, we fake that here. This allows us
   // to test the module without actually needing Google Test.
-  if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests") {
+  if (argc > 2 && std::string(argv[1]) == "--gtest_list_tests" &&
+      std::string(argv[2]).find("--gtest_output=json:") != std::string::npos) {
     std::cout << "test_list_test/test.\n";
     std::cout << "  case/0  # GetParam() = \"semicolon;\"\n";
     std::cout << "  case/1  # GetParam() = 'osb['\n";
     std::cout << "  case/2  # GetParam() = 'csb]'\n";
     std::cout << "  case/3  # GetParam() = 'S p a c e s'\n";
+
+    std::string output_param(argv[2]);
+    std::string::size_type split = output_param.find(":");
+    std::string filepath = output_param.substr(split + 1);
+    // The full file path is passed
+    std::ofstream ostrm(filepath.c_str(), std::ios::binary);
+    if (!ostrm) {
+      std::cerr << "Failed to create file: " << filepath.c_str() << std::endl;
+      return 1;
+    }
+    ostrm
+      << "{\n"
+         "    \"tests\": 4,\n"
+         "    \"name\": \"AllTests\",\n"
+         "    \"testsuites\": [\n"
+         "        {\n"
+         "            \"name\": \"test_list_test/test\",\n"
+         "            \"tests\": 4,\n"
+         "            \"testsuite\": [\n"
+         "                { \"name\": \"case/0\", \"value_param\": "
+         "\"\\\"semicolon;\\\"\", \"file\": \"file.cpp\", \"line\": 42 },\n"
+         "                { \"name\": \"case/1\", \"value_param\": "
+         "\"'osb['\", \"file\": \"file.cpp\", \"line\": 42 },\n"
+         "                { \"name\": \"case/2\", \"value_param\": "
+         "\"'csb]'\", \"file\": \"file.cpp\", \"line\": 42 },\n"
+         "                { \"name\": \"case/3\", \"value_param\": \"'S p a c "
+         "e s'\", \"file\": \"file.cpp\", \"line\": 42 }\n"
+         "            ]\n"
+         "        }\n"
+         "    ]\n"
+         "}";
   }
   return 0;
 }
diff --git a/Tests/RunCMake/GoogleTest/test_workdir.cpp b/Tests/RunCMake/GoogleTest/test_workdir.cpp
index c8d70d1..8a82942 100644
--- a/Tests/RunCMake/GoogleTest/test_workdir.cpp
+++ b/Tests/RunCMake/GoogleTest/test_workdir.cpp
@@ -19,13 +19,30 @@
   // the current directory. If we are not handling spaces in the
   // working directory correctly, the files we expect won't exist.
 
-  if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests") {
-    std::ifstream inFile("test_list_output.txt");
-    if (!inFile) {
+  if (argc > 2 && std::string(argv[1]) == "--gtest_list_tests" &&
+      std::string(argv[2]).find("--gtest_output=json:") != std::string::npos) {
+    std::ifstream inTestListFile("test_list_output.txt");
+    if (!inTestListFile) {
       std::cout << "ERROR: Failed to open test_list_output.txt" << std::endl;
       return 1;
     }
-    std::cout << inFile.rdbuf();
+    std::cout << inTestListFile.rdbuf();
+
+    std::ifstream inJsonFile("test_list_output.json");
+    if (!inJsonFile) {
+      std::cout << "ERROR: Failed to open test_list_output.json" << std::endl;
+      return 1;
+    }
+    std::string output_param(argv[2]);
+    std::string::size_type split = output_param.find(":");
+    std::string filepath = output_param.substr(split + 1);
+    // The full file path is passed
+    std::ofstream ostrm(filepath.c_str(), std::ios::binary);
+    if (!ostrm) {
+      std::cerr << "Failed to create file: " << filepath.c_str() << std::endl;
+      return 1;
+    }
+    ostrm << inJsonFile.rdbuf();
     return 0;
   }
 
diff --git a/Tests/RunCMake/GoogleTest/timeout_test.cpp b/Tests/RunCMake/GoogleTest/timeout_test.cpp
index 5506269..e09793c 100644
--- a/Tests/RunCMake/GoogleTest/timeout_test.cpp
+++ b/Tests/RunCMake/GoogleTest/timeout_test.cpp
@@ -1,3 +1,5 @@
+#define _CRT_SECURE_NO_WARNINGS // work around 'fopen' deprecation on WIN32
+
 #if defined(_WIN32)
 #  include <windows.h>
 #else
@@ -23,9 +25,38 @@
   // it only requires that we produce output in the expected format when
   // invoked with --gtest_list_tests. Thus, we fake that here. This allows us
   // to test the module without actually needing Google Test.
-  if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests") {
+  if (argc > 1 && std::string(argv[1]) == "--gtest_list_tests" &&
+      std::string(argv[2]).find("--gtest_output=json:") != std::string::npos) {
     printf("timeout.\n  case\n");
     fflush(stdout);
+
+    std::string output_param(argv[2]);
+    std::string::size_type split = output_param.find(":");
+    std::string filepath = output_param.substr(split + 1);
+    // The full file path is passed
+    FILE* ofile = fopen(filepath.c_str(), "wb");
+
+    if (!ofile) {
+      fprintf(stderr, "Failed to create file: %s\n", filepath.c_str());
+      return 1;
+    }
+    std::string json_output = "{\n"
+                              "      \"tests\": 1,\n"
+                              "      \"name\": \"AllTests\",\n"
+                              "      \"testsuites\": [\n"
+                              "          {\n"
+                              "              \"name\": \"timeout\",\n"
+                              "              \"tests\": 1,\n"
+                              "              \"testsuite\": [\n"
+                              "                  { \"name\": \"case\", "
+                              "\"file\": \"file.cpp\", \"line\": 42 }\n"
+                              "              ]\n"
+                              "          }\n"
+                              "      ]\n"
+                              "  }";
+    fprintf(ofile, "%s", json_output.c_str());
+    fclose(ofile);
+
 #ifdef discoverySleepSec
     sleepFor(discoverySleepSec);
 #endif
diff --git a/Tests/RunCMake/GoogleTest/xml_output.cpp b/Tests/RunCMake/GoogleTest/xml_output.cpp
index 743a472..e2ee7a5 100644
--- a/Tests/RunCMake/GoogleTest/xml_output.cpp
+++ b/Tests/RunCMake/GoogleTest/xml_output.cpp
@@ -19,6 +19,43 @@
       std::cout << "  case/0  # GetParam() = 42" << std::endl;
       std::cout << "  case/1  # GetParam() = \"string\"" << std::endl;
       std::cout << "  case/2  # GetParam() = \"path/like\"" << std::endl;
+    } else if (param.find("--gtest_output=json:") != std::string::npos) {
+      std::string::size_type split = param.find(":");
+      std::string filepath = param.substr(split + 1);
+      // The full file path is passed
+      std::ofstream ostrm(filepath.c_str(), std::ios::binary);
+      if (!ostrm) {
+        std::cerr << "Failed to create file: " << filepath.c_str()
+                  << std::endl;
+        return 1;
+      }
+      ostrm
+        << "{\n"
+           "    \"tests\": 4,\n"
+           "    \"name\": \"AllTests\",\n"
+           "    \"testsuites\": [\n"
+           "        {\n"
+           "            \"name\": \"GoogleTestXML\",\n"
+           "            \"tests\": 1,\n"
+           "            \"testsuite\": [\n"
+           "                { \"name\": \"Foo\", \"file\": \"file.cpp\", "
+           "\"line\": 42 }\n"
+           "            ]\n"
+           "        },\n"
+           "        {\n"
+           "            \"name\": \"GoogleTestXMLSpecial\\/cases\",\n"
+           "            \"tests\": 3,\n"
+           "            \"testsuite\": [\n"
+           "                { \"name\": \"case\\/0\", \"value_param\": "
+           "\"42\", \"file\": \"file2.cpp\", \"line\": 47 },\n"
+           "                { \"name\": \"case\\/1\", \"value_param\": "
+           "\"\\\"string\\\"\", \"file\": \"file2.cpp\", \"line\": 47 },\n"
+           "                { \"name\": \"case\\/2\", \"value_param\": "
+           "\"\\\"path/like\\\"\", \"file\": \"file2.cpp\", \"line\": 47 }\n"
+           "            ]\n"
+           "        }\n"
+           "    ]\n"
+           "}";
     } else if (param.find("--gtest_output=xml:") != std::string::npos) {
       std::string::size_type split = param.find(":");
       std::string filepath = param.substr(split + 1);
diff --git a/Tests/RunCMake/InstallPackageInfo/Appendix-check.cmake b/Tests/RunCMake/InstallPackageInfo/Appendix-check.cmake
index 864e731..92925d8 100644
--- a/Tests/RunCMake/InstallPackageInfo/Appendix-check.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/Appendix-check.cmake
@@ -5,11 +5,13 @@
 file(READ "${out_dir}/foo.cps" content)
 expect_value("${content}" "foo" "name")
 expect_value("${content}" "interface" "components" "mammal" "type")
+expect_value("${content}" "LGPL-3.0-or-later" "default_license")
 expect_value("${content}" "1.0" "version")
 
 file(READ "${out_dir}/foo-dog.cps" content)
 expect_value("${content}" "foo" "name")
 expect_value("${content}" "interface" "components" "canine" "type")
+expect_value("${content}" "GPL-3.0-or-later" "default_license")
 expect_missing("${content}" "version")
 
 expect_array("${content}" 1 "components" "canine" "requires")
diff --git a/Tests/RunCMake/InstallPackageInfo/Appendix.cmake b/Tests/RunCMake/InstallPackageInfo/Appendix.cmake
index fe67778..5f4222c 100644
--- a/Tests/RunCMake/InstallPackageInfo/Appendix.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/Appendix.cmake
@@ -5,5 +5,16 @@
 install(TARGETS mammal EXPORT mammal DESTINATION .)
 install(TARGETS canine EXPORT canine DESTINATION .)
 
-install(PACKAGE_INFO foo DESTINATION cps EXPORT mammal VERSION 1.0)
-install(PACKAGE_INFO foo DESTINATION cps EXPORT canine APPENDIX dog)
+install(
+  PACKAGE_INFO foo
+  DESTINATION cps
+  EXPORT mammal
+  VERSION 1.0
+  DEFAULT_LICENSE "LGPL-3.0-or-later")
+
+install(
+  PACKAGE_INFO foo
+  DESTINATION cps
+  EXPORT canine
+  APPENDIX dog
+  DEFAULT_LICENSE "GPL-3.0-or-later")
diff --git a/Tests/RunCMake/InstallPackageInfo/BadArgs2-stderr.txt b/Tests/RunCMake/InstallPackageInfo/BadArgs2-stderr.txt
index a50f759..1df7278 100644
--- a/Tests/RunCMake/InstallPackageInfo/BadArgs2-stderr.txt
+++ b/Tests/RunCMake/InstallPackageInfo/BadArgs2-stderr.txt
@@ -5,6 +5,12 @@
 
 
 CMake Error at BadArgs2.cmake:[0-9]+ \(install\):
+  install APPENDIX and LICENSE are mutually exclusive.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)
+
+
+CMake Error at BadArgs2.cmake:[0-9]+ \(install\):
   install APPENDIX and DESCRIPTION are mutually exclusive.
 Call Stack \(most recent call first\):
   CMakeLists\.txt:3 \(include\)
diff --git a/Tests/RunCMake/InstallPackageInfo/BadArgs2.cmake b/Tests/RunCMake/InstallPackageInfo/BadArgs2.cmake
index b4d405f..4462907 100644
--- a/Tests/RunCMake/InstallPackageInfo/BadArgs2.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/BadArgs2.cmake
@@ -1,8 +1,10 @@
 add_library(foo INTERFACE)
 install(TARGETS foo EXPORT foo DESTINATION .)
-install(PACKAGE_INFO test EXPORT foo APPENDIX test VERSION 1.0)
-install(PACKAGE_INFO test EXPORT foo APPENDIX test DESCRIPTION "Test")
-install(PACKAGE_INFO test EXPORT foo APPENDIX test HOMEPAGE_URL "example.com")
-install(PACKAGE_INFO test EXPORT foo APPENDIX test DEFAULT_TARGETS foo)
-install(PACKAGE_INFO test EXPORT foo APPENDIX test DEFAULT_CONFIGURATIONS test)
-install(PACKAGE_INFO test EXPORT foo APPENDIX test PROJECT foo)
+set(args PACKAGE_INFO test EXPORT foo APPENDIX test)
+install(${args} VERSION 1.0)
+install(${args} LICENSE "BSD-3-Clause AND CC-BY-SA-4.0")
+install(${args} DESCRIPTION "Test")
+install(${args} HOMEPAGE_URL "example.com")
+install(${args} DEFAULT_TARGETS foo)
+install(${args} DEFAULT_CONFIGURATIONS test)
+install(${args} PROJECT foo)
diff --git a/Tests/RunCMake/InstallPackageInfo/Config-check.cmake b/Tests/RunCMake/InstallPackageInfo/Config-check.cmake
new file mode 100644
index 0000000..7739681
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/Config-check.cmake
@@ -0,0 +1,16 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/Config-build/CMakeFiles/Export/510c5684a4a8a792eadfb55bc9744983")
+
+macro(check_config CONFIG)
+  string(TOLOWER "${CONFIG}" CONFIG_LOWER)
+  file(READ "${out_dir}/foo@${CONFIG_LOWER}.cps" content)
+  expect_value("${content}" "${CONFIG}" "configuration")
+endmacro()
+
+if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  check_config(FooConfig)
+  check_config(BarConfig)
+else()
+  check_config(TestConfig)
+endif()
diff --git a/Tests/RunCMake/InstallPackageInfo/Config.cmake b/Tests/RunCMake/InstallPackageInfo/Config.cmake
new file mode 100644
index 0000000..ce53713
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/Config.cmake
@@ -0,0 +1,13 @@
+project(Config CXX)
+
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+  set(CMAKE_CONFIGURATION_TYPES "FooConfig;BarConfig" CACHE STRING "" FORCE)
+else()
+  set(CMAKE_BUILD_TYPE "TestConfig" CACHE STRING "" FORCE)
+endif()
+
+add_library(foo foo.cxx)
+
+install(TARGETS foo EXPORT foo)
+install(PACKAGE_INFO foo DESTINATION cps EXPORT foo)
diff --git a/Tests/RunCMake/InstallPackageInfo/DependencyVersionCMake-check.cmake b/Tests/RunCMake/InstallPackageInfo/DependencyVersionCMake-check.cmake
new file mode 100644
index 0000000..3bca2c9
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/DependencyVersionCMake-check.cmake
@@ -0,0 +1,15 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/DependencyVersionCMake-build/CMakeFiles/Export/5058f1af8388633f609cadb75a75dc9d")
+
+file(READ "${out_dir}/foo.cps" content)
+expect_value("${content}" "foo" "name")
+expect_array("${content}" 1 "requires" "bar" "components")
+expect_value("${content}" "bar" "requires" "bar" "components" 0)
+expect_value("${content}" "1.3.5" "requires" "bar" "version")
+expect_array("${content}" 1 "requires" "bar" "hints")
+expect_value("${content}" "${CMAKE_CURRENT_LIST_DIR}/config" "requires" "bar" "hints" 0)
+
+string(JSON component GET "${content}" "components" "foo")
+expect_array("${component}" 1 "requires")
+expect_value("${component}" "bar:bar" "requires" 0)
diff --git a/Tests/RunCMake/InstallPackageInfo/DependencyVersionCMake.cmake b/Tests/RunCMake/InstallPackageInfo/DependencyVersionCMake.cmake
new file mode 100644
index 0000000..28f129f
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/DependencyVersionCMake.cmake
@@ -0,0 +1,11 @@
+find_package(
+    bar 1.3.4 REQUIRED CONFIG
+    NO_DEFAULT_PATH
+    PATHS ${CMAKE_CURRENT_LIST_DIR}/config
+)
+
+add_library(foo INTERFACE)
+target_link_libraries(foo INTERFACE bar::bar)
+
+install(TARGETS foo EXPORT foo)
+install(PACKAGE_INFO foo EXPORT foo DESTINATION .)
diff --git a/Tests/RunCMake/InstallPackageInfo/DependencyVersionCps-check.cmake b/Tests/RunCMake/InstallPackageInfo/DependencyVersionCps-check.cmake
new file mode 100644
index 0000000..95c01cd
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/DependencyVersionCps-check.cmake
@@ -0,0 +1,15 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/DependencyVersionCps-build/CMakeFiles/Export/5058f1af8388633f609cadb75a75dc9d")
+
+file(READ "${out_dir}/foo.cps" content)
+expect_value("${content}" "foo" "name")
+expect_array("${content}" 1 "requires" "baz" "components")
+expect_value("${content}" "baz" "requires" "baz" "components" 0)
+expect_value("${content}" "1.3.5" "requires" "baz" "version")
+expect_array("${content}" 1 "requires" "baz" "hints")
+expect_value("${content}" "${CMAKE_CURRENT_LIST_DIR}/cps" "requires" "baz" "hints" 0)
+
+string(JSON component GET "${content}" "components" "foo")
+expect_array("${component}" 1 "requires")
+expect_value("${component}" "baz:baz" "requires" 0)
diff --git a/Tests/RunCMake/InstallPackageInfo/DependencyVersionCps.cmake b/Tests/RunCMake/InstallPackageInfo/DependencyVersionCps.cmake
new file mode 100644
index 0000000..1453d52
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/DependencyVersionCps.cmake
@@ -0,0 +1,11 @@
+find_package(
+    baz 1.3.4 REQUIRED
+    NO_DEFAULT_PATH
+    PATHS ${CMAKE_CURRENT_LIST_DIR}
+)
+
+add_library(foo INTERFACE)
+target_link_libraries(foo INTERFACE baz::baz)
+
+install(TARGETS foo EXPORT foo)
+install(PACKAGE_INFO foo EXPORT foo DESTINATION .)
diff --git a/Tests/RunCMake/InstallPackageInfo/EmptyConfig-check.cmake b/Tests/RunCMake/InstallPackageInfo/EmptyConfig-check.cmake
new file mode 100644
index 0000000..49ca07a
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/EmptyConfig-check.cmake
@@ -0,0 +1,7 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/EmptyConfig-build/CMakeFiles/Export/510c5684a4a8a792eadfb55bc9744983")
+
+file(READ "${out_dir}/foo@noconfig.cps" content)
+
+expect_value("${content}" "noconfig" "configuration")
diff --git a/Tests/RunCMake/InstallPackageInfo/EmptyConfig.cmake b/Tests/RunCMake/InstallPackageInfo/EmptyConfig.cmake
new file mode 100644
index 0000000..9641b54
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/EmptyConfig.cmake
@@ -0,0 +1,9 @@
+project(EmptyConfig CXX)
+
+set(CMAKE_BUILD_TYPE "" CACHE STRING "" FORCE)
+set(CMAKE_CONFIGURATION_TYPES "" CACHE STRING "" FORCE)
+
+add_library(foo foo.cxx)
+
+install(TARGETS foo EXPORT foo)
+install(PACKAGE_INFO foo DESTINATION cps EXPORT foo)
diff --git a/Tests/RunCMake/InstallPackageInfo/FileSetHeaders-check.cmake b/Tests/RunCMake/InstallPackageInfo/FileSetHeaders-check.cmake
new file mode 100644
index 0000000..c2652e2
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/FileSetHeaders-check.cmake
@@ -0,0 +1,28 @@
+include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
+
+set(out_dir "${RunCMake_BINARY_DIR}/FileSetHeaders-build/CMakeFiles/Export/510c5684a4a8a792eadfb55bc9744983")
+
+file(READ "${out_dir}/foo.cps" content)
+
+string(JSON component GET "${content}" "components" "foo")
+
+expect_array("${component}" 1 "includes")
+expect_value("${component}" "@prefix@/no_genex" "includes" 0)
+
+file(GLOB configs "${out_dir}/foo@*.cps")
+list(LENGTH configs configs_len)
+
+if(NOT configs_len)
+  set(RunCMake_TEST_FAILED
+    "No configuration-specific CPS files were generated" PARENT_SCOPE)
+  return()
+endif()
+
+foreach(config ${configs})
+  file(READ "${config}" content)
+
+  string(JSON component GET "${content}" "components" "foo")
+
+  expect_array("${component}" 1 "includes")
+  expect_value("${component}" "@prefix@/genex" "includes" 0)
+endforeach()
diff --git a/Tests/RunCMake/InstallPackageInfo/FileSetHeaders.cmake b/Tests/RunCMake/InstallPackageInfo/FileSetHeaders.cmake
new file mode 100644
index 0000000..21347e5
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/FileSetHeaders.cmake
@@ -0,0 +1,38 @@
+add_library(foo INTERFACE)
+
+target_sources(foo
+  INTERFACE
+    FILE_SET no_genex
+    TYPE HEADERS
+
+  INTERFACE
+    FILE_SET no_genex_dup
+    TYPE HEADERS
+
+  INTERFACE
+    FILE_SET genex
+    TYPE HEADERS
+
+  INTERFACE
+    FILE_SET genex_dup
+    TYPE HEADERS
+)
+
+install(
+  TARGETS foo
+  EXPORT foo
+  DESTINATION .
+
+  FILE_SET no_genex
+    DESTINATION no_genex
+
+  FILE_SET no_genex_dup
+    DESTINATION no_genex
+
+  FILE_SET genex
+    DESTINATION $<$<CONFIG:FAKE_CONFIG>:FAKE_DEST>genex
+
+  FILE_SET genex_dup
+    DESTINATION $<$<CONFIG:FAKE_CONFIG>:FAKE_DEST>genex
+)
+install(PACKAGE_INFO foo DESTINATION cps EXPORT foo)
diff --git a/Tests/RunCMake/InstallPackageInfo/Metadata-check.cmake b/Tests/RunCMake/InstallPackageInfo/Metadata-check.cmake
index 7eca3b0..75516d5 100644
--- a/Tests/RunCMake/InstallPackageInfo/Metadata-check.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/Metadata-check.cmake
@@ -15,5 +15,7 @@
 expect_value("${content}" "release" "configurations" 0)
 expect_value("${content}" "debug" "configurations" 1)
 
+expect_value("${content}" "BSD-3-Clause" "default_license")
+expect_value("${content}" "BSD-3-Clause AND CC-BY-SA-4.0" "license")
 expect_value("${content}" "Sample package" "description")
 expect_value("${content}" "https://www.example.com/package/foo" "website")
diff --git a/Tests/RunCMake/InstallPackageInfo/Metadata.cmake b/Tests/RunCMake/InstallPackageInfo/Metadata.cmake
index d551f3b..f14fe93 100644
--- a/Tests/RunCMake/InstallPackageInfo/Metadata.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/Metadata.cmake
@@ -9,6 +9,8 @@
   COMPAT_VERSION 1.2.0
   DEFAULT_TARGETS foo
   DEFAULT_CONFIGURATIONS release debug
+  LICENSE "BSD-3-Clause AND CC-BY-SA-4.0"
+  DEFAULT_LICENSE "BSD-3-Clause"
   DESCRIPTION "Sample package"
   HOMEPAGE_URL "https://www.example.com/package/foo"
   )
diff --git a/Tests/RunCMake/InstallPackageInfo/PerConfigGeneration-check.cmake b/Tests/RunCMake/InstallPackageInfo/PerConfigGeneration-check.cmake
deleted file mode 100644
index 5ff99a5..0000000
--- a/Tests/RunCMake/InstallPackageInfo/PerConfigGeneration-check.cmake
+++ /dev/null
@@ -1,24 +0,0 @@
-include(${CMAKE_CURRENT_LIST_DIR}/Assertions.cmake)
-
-set(out_dir "${RunCMake_BINARY_DIR}/PerConfigGeneration-build/CMakeFiles/Export/510c5684a4a8a792eadfb55bc9744983")
-
-macro(check_config)
-  string(TOLOWER "${config}" config_lower)
-  if(NOT EXISTS "${out_dir}/foo@${config_lower}.cps")
-    set(RunCMake_TEST_FAILED
-      "Configuration file for '${config}' does not exist")
-    return()
-  endif()
-
-  file(READ "${out_dir}/foo@${config_lower}.cps" content)
-  expect_value("${content}" "${config}" "configuration")
-endmacro()
-
-if(RunCMake_GENERATOR_IS_MULTI_CONFIG)
-  foreach(config ${CMAKE_CONFIGURATION_TYPES})
-    check_config()
-  endforeach()
-else()
-  include(${RunCMake_TEST_BINARY_DIR}/build_type.cmake)
-  check_config()
-endif()
diff --git a/Tests/RunCMake/InstallPackageInfo/PerConfigGeneration.cmake b/Tests/RunCMake/InstallPackageInfo/PerConfigGeneration.cmake
deleted file mode 100644
index 4f4c149..0000000
--- a/Tests/RunCMake/InstallPackageInfo/PerConfigGeneration.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-project(PerConfigGeneration CXX)
-
-set(config ${CMAKE_BUILD_TYPE})
-if(NOT config)
-  set(config noconfig)
-endif()
-
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/build_type.cmake" "set(config \"${config}\")")
-
-add_library(foo foo.cxx)
-
-install(TARGETS foo EXPORT foo)
-install(PACKAGE_INFO foo DESTINATION cps EXPORT foo)
diff --git a/Tests/RunCMake/InstallPackageInfo/ProjectMetadata-check.cmake b/Tests/RunCMake/InstallPackageInfo/ProjectMetadata-check.cmake
index 5c39b3f..b09b065 100644
--- a/Tests/RunCMake/InstallPackageInfo/ProjectMetadata-check.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/ProjectMetadata-check.cmake
@@ -6,6 +6,7 @@
 expect_value("${content}" "foo" "name")
 expect_value("${content}" "1.2.3" "version")
 expect_value("${content}" "1.1.0" "compat_version")
+expect_value("${content}" "BSD-3-Clause" "license")
 expect_value("${content}" "Sample package" "description")
 expect_value("${content}" "https://www.example.com/package/foo" "website")
 
@@ -13,6 +14,7 @@
 expect_value("${content}" "test1" "name")
 expect_value("${content}" "1.2.3" "version")
 expect_value("${content}" "1.1.0" "compat_version")
+expect_value("${content}" "BSD-3-Clause" "license")
 expect_value("${content}" "Sample package" "description")
 expect_value("${content}" "https://www.example.com/package/foo" "website")
 
@@ -20,5 +22,6 @@
 expect_value("${content}" "test2" "name")
 expect_value("${content}" "1.4.7" "version")
 expect_missing("${content}" "compat_version")
+expect_value("${content}" "Apache-2.0" "license")
 expect_value("${content}" "Don't inherit" "description")
 expect_value("${content}" "https://www.example.com/package/bar" "website")
diff --git a/Tests/RunCMake/InstallPackageInfo/ProjectMetadata.cmake b/Tests/RunCMake/InstallPackageInfo/ProjectMetadata.cmake
index e86372f..3111150 100644
--- a/Tests/RunCMake/InstallPackageInfo/ProjectMetadata.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/ProjectMetadata.cmake
@@ -1,6 +1,7 @@
 project(foo
   VERSION 1.2.3
   COMPAT_VERSION 1.1.0
+  SPDX_LICENSE "BSD-3-Clause"
   DESCRIPTION "Sample package"
   HOMEPAGE_URL "https://www.example.com/package/foo"
   )
@@ -30,6 +31,7 @@
   EXPORT foo
   PROJECT foo
   VERSION 1.4.7
+  LICENSE "Apache-2.0"
   DESCRIPTION "Don't inherit"
   HOMEPAGE_URL "https://www.example.com/package/bar"
   )
diff --git a/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake b/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake
index bcd2ef8..82c0d90 100644
--- a/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake
+++ b/Tests/RunCMake/InstallPackageInfo/RunCMakeTest.cmake
@@ -8,6 +8,7 @@
 set(RunCMake_TEST_OPTIONS
   -Wno-dev
   "-DCMAKE_EXPERIMENTAL_EXPORT_PACKAGE_INFO:STRING=b80be207-778e-46ba-8080-b23bba22639e"
+  "-DCMAKE_EXPERIMENTAL_FIND_CPS_PACKAGES:STRING=e82e467b-f997-4464-8ace-b00808fff261"
   )
 
 function(run_cmake_install test)
@@ -48,5 +49,9 @@
 run_cmake(TargetTypes)
 run_cmake(DependsMultiple)
 run_cmake(DependsMultipleNotInstalled)
-run_cmake(PerConfigGeneration)
+run_cmake(Config)
+run_cmake(EmptyConfig)
+run_cmake(FileSetHeaders)
+run_cmake(DependencyVersionCMake)
+run_cmake(DependencyVersionCps)
 run_cmake_install(Destination)
diff --git a/Tests/RunCMake/InstallPackageInfo/config/bar-config-version.cmake b/Tests/RunCMake/InstallPackageInfo/config/bar-config-version.cmake
new file mode 100644
index 0000000..ff683d6
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/config/bar-config-version.cmake
@@ -0,0 +1,29 @@
+set(PACKAGE_VERSION "1.3.5")
+
+if (PACKAGE_FIND_VERSION_RANGE)
+  # Check for a version range
+  if (PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_RANGE_MIN)
+    set(PACKAGE_VERSION_COMPATIBLE FALSE)
+  else ()
+    if (PACKAGE_FIND_VERSION_RANGE_MAX)
+      if (PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_RANGE_MAX)
+        set(PACKAGE_VERSION_COMPATIBLE FALSE)
+      else ()
+        set(PACKAGE_VERSION_COMPATIBLE TRUE)
+      endif ()
+    else ()
+      set(PACKAGE_VERSION_COMPATIBLE TRUE)
+    endif ()
+  endif ()
+
+elseif (PACKAGE_FIND_VERSION)
+  # Check for a specific version or minimum version
+  if (PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
+    set(PACKAGE_VERSION_COMPATIBLE FALSE)
+  else ()
+    set(PACKAGE_VERSION_COMPATIBLE TRUE)
+    if (PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION)
+      set(PACKAGE_VERSION_EXACT TRUE)
+    endif ()
+  endif ()
+endif ()
diff --git a/Tests/RunCMake/InstallPackageInfo/config/bar-config.cmake b/Tests/RunCMake/InstallPackageInfo/config/bar-config.cmake
new file mode 100644
index 0000000..d17ed84
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/config/bar-config.cmake
@@ -0,0 +1 @@
+add_library(bar::bar INTERFACE IMPORTED)
diff --git a/Tests/RunCMake/InstallPackageInfo/cps/baz.cps b/Tests/RunCMake/InstallPackageInfo/cps/baz.cps
new file mode 100644
index 0000000..6cf1042
--- /dev/null
+++ b/Tests/RunCMake/InstallPackageInfo/cps/baz.cps
@@ -0,0 +1,14 @@
+{
+  "components" :
+  {
+    "baz" :
+    {
+      "type" : "interface"
+    }
+  },
+  "cps_path" : "@prefix@/cps",
+  "cps_version" : "0.13.0",
+  "compat_version": "1.0.0",
+  "name" : "baz",
+  "version": "1.3.5"
+}
diff --git a/Tests/RunCMake/Instrumentation/RunCMakeTest.cmake b/Tests/RunCMake/Instrumentation/RunCMakeTest.cmake
index 39f06a7..15fd8f1 100644
--- a/Tests/RunCMake/Instrumentation/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Instrumentation/RunCMakeTest.cmake
@@ -9,7 +9,7 @@
     "BUILD;BUILD_MAKE_PROGRAM;INSTALL;TEST;COPY_QUERIES;COPY_QUERIES_GENERATED;NO_WARN;STATIC_QUERY;DYNAMIC_QUERY;INSTALL_PARALLEL;MANUAL_HOOK"
     "CHECK_SCRIPT;CONFIGURE_ARG" "" ${ARGN})
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test})
-  set(uuid "a37d1069-1972-4901-b9c9-f194aaf2b6e0")
+  set(uuid "d16a3082-c4e1-489b-b90c-55750a334f27")
   set(v1 ${RunCMake_TEST_BINARY_DIR}/.cmake/instrumentation-${uuid}/v1)
   set(query_dir ${CMAKE_CURRENT_LIST_DIR}/query)
 
@@ -66,7 +66,11 @@
     run_cmake_command(${test}-build ${CMAKE_COMMAND} --build . --config Debug)
   endif()
   if (ARGS_BUILD_MAKE_PROGRAM)
+    set(RunCMake_TEST_OUTPUT_MERGE 1)
+    # Force reconfigure to test for double preBuild & postBuild hooks
+    file(TOUCH ${RunCMake_TEST_BINARY_DIR}/CMakeCache.txt)
     run_cmake_command(${test}-make-program ${RunCMake_MAKE_PROGRAM})
+    unset(RunCMake_TEST_OUTPUT_MERGE)
   endif()
   if (ARGS_INSTALL)
     run_cmake_command(${test}-install ${CMAKE_COMMAND} --install . --prefix install --config Debug)
@@ -90,7 +94,7 @@
 endfunction()
 
 # Bad Queries
-instrument(bad-query)
+instrument(bad-option)
 instrument(bad-hook)
 instrument(empty)
 instrument(bad-version)
@@ -100,7 +104,7 @@
 instrument(hooks-2 BUILD INSTALL TEST)
 instrument(hooks-no-callbacks MANUAL_HOOK)
 
-# Check data file contents
+# Check data file contents for optional query data
 instrument(no-query BUILD INSTALL TEST
   CHECK_SCRIPT check-data-dir.cmake)
 instrument(dynamic-query BUILD INSTALL TEST DYNAMIC_QUERY
@@ -126,9 +130,32 @@
   COPY_QUERIES_GENERATED
   CHECK_SCRIPT check-data-dir.cmake
 )
+instrument(cmake-command-cmake-build NO_WARN
+  BUILD
+  CHECK_SCRIPT check-no-make-program-hooks.cmake
+)
 
-# FIXME(#26668) This does not work on Windows
-if (UNIX)
+if(RunCMake_GENERATOR STREQUAL "MSYS Makefiles")
+  # FIXME(#27079): This does not work for MSYS Makefiles.
+  set(Skip_BUILD_MAKE_PROGRAM_Case 1)
+elseif(RunCMake_GENERATOR STREQUAL "NMake Makefiles")
+ execute_process(
+   COMMAND "${RunCMake_MAKE_PROGRAM}" -?
+   OUTPUT_VARIABLE nmake_out
+   ERROR_VARIABLE nmake_out
+   RESULT_VARIABLE nmake_res
+   OUTPUT_STRIP_TRAILING_WHITESPACE
+   )
+   if(nmake_res EQUAL 0 AND nmake_out MATCHES "Program Maintenance Utility[^\n]+Version ([1-9][0-9.]+)")
+     set(nmake_version "${CMAKE_MATCH_1}")
+   else()
+     message(FATAL_ERROR "'nmake -?' reported:\n${nmake_out}")
+   endif()
+   if(nmake_version VERSION_LESS 9)
+     set(Skip_BUILD_MAKE_PROGRAM_Case 1)
+   endif()
+endif()
+if(NOT Skip_BUILD_MAKE_PROGRAM_Case)
   instrument(cmake-command-make-program NO_WARN
     BUILD_MAKE_PROGRAM
     CHECK_SCRIPT check-make-program-hooks.cmake)
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/Instrumentation/bad-option-result.txt
similarity index 100%
rename from Tests/RunCMake/Instrumentation/bad-query-result.txt
rename to Tests/RunCMake/Instrumentation/bad-option-result.txt
diff --git a/Tests/RunCMake/Instrumentation/bad-option-stderr.txt b/Tests/RunCMake/Instrumentation/bad-option-stderr.txt
new file mode 100644
index 0000000..91af446
--- /dev/null
+++ b/Tests/RunCMake/Instrumentation/bad-option-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error: Could not load instrumentation queries from [^
+]+:
+bad-option.json:[0-9]+: Not a valid option: "bad option"
+  "options": \["staticSystemInformation", "bad option"\]
+                                         \^$
diff --git a/Tests/RunCMake/Instrumentation/bad-query-stderr.txt b/Tests/RunCMake/Instrumentation/bad-query-stderr.txt
deleted file mode 100644
index 93be7e4..0000000
--- a/Tests/RunCMake/Instrumentation/bad-query-stderr.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-^CMake Error: Could not load instrumentation queries from [^
-]+:
-bad-query.json:[0-9]+: Not a valid query: "bad query"
-  "queries": \["staticSystemInformation", "bad query"\]
-                                         \^$
diff --git a/Tests/RunCMake/Instrumentation/check-no-make-program-hooks.cmake b/Tests/RunCMake/Instrumentation/check-no-make-program-hooks.cmake
new file mode 100644
index 0000000..b178091
--- /dev/null
+++ b/Tests/RunCMake/Instrumentation/check-no-make-program-hooks.cmake
@@ -0,0 +1,6 @@
+if (EXISTS ${v1}/preBuild.hook OR EXISTS ${v1}/postBuild.hook)
+  set(RunCMake_TEST_FAILED "Got unexpected preBuild/postBuild hooks.")
+endif()
+if (NOT EXISTS ${v1}/postCMakeBuild.hook)
+  set(RunCMake_TEST_FAILED "Missing expected postCMakeBuild hook.")
+endif()
diff --git a/Tests/RunCMake/Instrumentation/cmake-command-bad-api-version-stderr.txt b/Tests/RunCMake/Instrumentation/cmake-command-bad-api-version-stderr.txt
index ab172e0..6c14718 100644
--- a/Tests/RunCMake/Instrumentation/cmake-command-bad-api-version-stderr.txt
+++ b/Tests/RunCMake/Instrumentation/cmake-command-bad-api-version-stderr.txt
@@ -1,6 +1,6 @@
 CMake Error at [^
 ]*\(cmake_instrumentation\):
-  cmake_instrumentation QUERY subcommand given an unsupported API_VERSION "0"
-  \(the only currently supported version is 1\).
+  cmake_instrumentation given an unsupported API_VERSION "0" \(the only
+  currently supported version is 1\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:6 \(include\)
diff --git a/Tests/RunCMake/Instrumentation/cmake-command-missing-version-stderr.txt b/Tests/RunCMake/Instrumentation/cmake-command-missing-version-stderr.txt
index 0d1d8c3..71937ea 100644
--- a/Tests/RunCMake/Instrumentation/cmake-command-missing-version-stderr.txt
+++ b/Tests/RunCMake/Instrumentation/cmake-command-missing-version-stderr.txt
@@ -1,6 +1,6 @@
 CMake Error at [^
 ]*\(cmake_instrumentation\):
-  cmake_instrumentation QUERY subcommand given an unsupported DATA_VERSION ""
-  \(the only currently supported version is 1\).
+  cmake_instrumentation given an unsupported DATA_VERSION "" \(the only
+  currently supported version is 1\).
 Call Stack \(most recent call first\):
   CMakeLists.txt:6 \(include\)
diff --git a/Tests/RunCMake/Instrumentation/hook.cmake b/Tests/RunCMake/Instrumentation/hook.cmake
index a139a37..95a58a0 100644
--- a/Tests/RunCMake/Instrumentation/hook.cmake
+++ b/Tests/RunCMake/Instrumentation/hook.cmake
@@ -53,27 +53,32 @@
 endforeach()
 
 has_key_index(staticSystemInformation "${contents}" ${hasStaticInfo})
-has_key_index(OSName "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(OSPlatform "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(OSRelease "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(OSVersion "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(familyId "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(hostname "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(is64Bits "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(modelId "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(numberOfLogicalCPU "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(numberOfPhysicalCPU "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(processorAPICID "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(processorCacheSize "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(processorClockFrequency "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(processorName "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(totalPhysicalMemory "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(totalVirtualMemory "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(vendorID "${staticSystemInformation}" ${hasStaticInfo})
-has_key_index(vendorString "${staticSystemInformation}" ${hasStaticInfo})
+if (NOT hasStaticInfo STREQUAL UNEXPECTED)
+  has_key_index(OSName "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(OSPlatform "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(OSRelease "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(OSVersion "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(familyId "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(hostname "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(is64Bits "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(modelId "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(numberOfLogicalCPU "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(numberOfPhysicalCPU "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(processorAPICID "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(processorCacheSize "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(processorClockFrequency "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(processorName "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(totalPhysicalMemory "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(totalVirtualMemory "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(vendorID "${staticSystemInformation}" ${hasStaticInfo})
+  has_key_index(vendorString "${staticSystemInformation}" ${hasStaticInfo})
+endif()
 
 get_filename_component(dataDir ${index} DIRECTORY)
 get_filename_component(v1 ${dataDir} DIRECTORY)
+if (EXISTS ${v1}/${hook}.hook)
+  add_error("Received multiple triggers of the same hook: ${hook}")
+endif()
 file(WRITE ${v1}/${hook}.hook "${ERROR_MESSAGE}")
 
 if (NOT ERROR_MESSAGE MATCHES "^$")
diff --git a/Tests/RunCMake/Instrumentation/project/CMakeLists.txt b/Tests/RunCMake/Instrumentation/project/CMakeLists.txt
index 0d90faf..a6fa16b 100644
--- a/Tests/RunCMake/Instrumentation/project/CMakeLists.txt
+++ b/Tests/RunCMake/Instrumentation/project/CMakeLists.txt
@@ -2,7 +2,7 @@
 project(instrumentation)
 enable_testing()
 if (EXISTS ${INSTRUMENT_COMMAND_FILE})
-  set(CMAKE_EXPERIMENTAL_INSTRUMENTATION "a37d1069-1972-4901-b9c9-f194aaf2b6e0")
+  set(CMAKE_EXPERIMENTAL_INSTRUMENTATION "d16a3082-c4e1-489b-b90c-55750a334f27")
   include(${INSTRUMENT_COMMAND_FILE})
 endif()
 
diff --git a/Tests/RunCMake/Instrumentation/query/bad-option.json.in b/Tests/RunCMake/Instrumentation/query/bad-option.json.in
new file mode 100644
index 0000000..215b534
--- /dev/null
+++ b/Tests/RunCMake/Instrumentation/query/bad-option.json.in
@@ -0,0 +1,4 @@
+{
+  "version": 1,
+  "options": ["staticSystemInformation", "bad option"]
+}
diff --git a/Tests/RunCMake/Instrumentation/query/bad-query.json.in b/Tests/RunCMake/Instrumentation/query/bad-query.json.in
deleted file mode 100644
index 5bd4054..0000000
--- a/Tests/RunCMake/Instrumentation/query/bad-query.json.in
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "version": 1,
-  "queries": ["staticSystemInformation", "bad query"]
-}
diff --git a/Tests/RunCMake/Instrumentation/query/both-query.json.in b/Tests/RunCMake/Instrumentation/query/both-query.json.in
index 839361f..7a34ac8 100644
--- a/Tests/RunCMake/Instrumentation/query/both-query.json.in
+++ b/Tests/RunCMake/Instrumentation/query/both-query.json.in
@@ -1,6 +1,6 @@
 {
   "version": 1,
-  "queries": [
+  "options": [
     "staticSystemInformation",
     "dynamicSystemInformation"
   ]
diff --git a/Tests/RunCMake/Instrumentation/query/cmake-command-cmake-build.cmake b/Tests/RunCMake/Instrumentation/query/cmake-command-cmake-build.cmake
new file mode 100644
index 0000000..434ee11
--- /dev/null
+++ b/Tests/RunCMake/Instrumentation/query/cmake-command-cmake-build.cmake
@@ -0,0 +1,7 @@
+file(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}/../hook.cmake" hook_path)
+cmake_instrumentation(
+  API_VERSION 1
+  DATA_VERSION 1
+  HOOKS preBuild postBuild postCMakeBuild
+  CALLBACK ${CMAKE_COMMAND} -P ${hook_path} 0
+)
diff --git a/Tests/RunCMake/Instrumentation/query/cmake-command-data.cmake b/Tests/RunCMake/Instrumentation/query/cmake-command-data.cmake
index 5c238fd..36107cf 100644
--- a/Tests/RunCMake/Instrumentation/query/cmake-command-data.cmake
+++ b/Tests/RunCMake/Instrumentation/query/cmake-command-data.cmake
@@ -1,5 +1,5 @@
 cmake_instrumentation(
   API_VERSION 1
   DATA_VERSION 1
-  QUERIES dynamicSystemInformation
+  OPTIONS dynamicSystemInformation
 )
diff --git a/Tests/RunCMake/Instrumentation/query/cmake-command-parallel-install.cmake b/Tests/RunCMake/Instrumentation/query/cmake-command-parallel-install.cmake
index 237f14e..0cd213b 100644
--- a/Tests/RunCMake/Instrumentation/query/cmake-command-parallel-install.cmake
+++ b/Tests/RunCMake/Instrumentation/query/cmake-command-parallel-install.cmake
@@ -2,5 +2,5 @@
 cmake_instrumentation(
   API_VERSION 1
   DATA_VERSION 1
-  QUERIES dynamicSystemInformation
+  OPTIONS dynamicSystemInformation
 )
diff --git a/Tests/RunCMake/Instrumentation/query/cmake-command.cmake b/Tests/RunCMake/Instrumentation/query/cmake-command.cmake
index 72e9b41..b220554 100644
--- a/Tests/RunCMake/Instrumentation/query/cmake-command.cmake
+++ b/Tests/RunCMake/Instrumentation/query/cmake-command.cmake
@@ -8,6 +8,7 @@
     API_VERSION 1
     DATA_VERSION 1
     HOOKS postGenerate
+    OPTIONS cdashSubmit cdashVerbose
     CALLBACK ${CMAKE_COMMAND} -E echo callback1
   )
   # Query 2
@@ -15,7 +16,7 @@
     API_VERSION 1
     DATA_VERSION 1
     HOOKS postCMakeBuild
-    QUERIES staticSystemInformation dynamicSystemInformation
+    OPTIONS staticSystemInformation dynamicSystemInformation
     CALLBACK ${CMAKE_COMMAND} -E echo callback2
     CALLBACK ${CMAKE_COMMAND} -E echo callback3
   )
diff --git a/Tests/RunCMake/Instrumentation/query/dynamic-query.json.in b/Tests/RunCMake/Instrumentation/query/dynamic-query.json.in
index 839361f..7a34ac8 100644
--- a/Tests/RunCMake/Instrumentation/query/dynamic-query.json.in
+++ b/Tests/RunCMake/Instrumentation/query/dynamic-query.json.in
@@ -1,6 +1,6 @@
 {
   "version": 1,
-  "queries": [
+  "options": [
     "staticSystemInformation",
     "dynamicSystemInformation"
   ]
diff --git a/Tests/RunCMake/Instrumentation/query/generated/query-0.json.in b/Tests/RunCMake/Instrumentation/query/generated/query-0.json.in
index d6b0a1a..352a6a8 100644
--- a/Tests/RunCMake/Instrumentation/query/generated/query-0.json.in
+++ b/Tests/RunCMake/Instrumentation/query/generated/query-0.json.in
@@ -1,6 +1,6 @@
 {
   "callbacks" : [],
   "hooks" : [],
-  "queries" : [],
+  "options" : [],
   "version": 1
 }
diff --git a/Tests/RunCMake/Instrumentation/query/generated/query-1.json.in b/Tests/RunCMake/Instrumentation/query/generated/query-1.json.in
index e5e6c35..5a77c5c 100644
--- a/Tests/RunCMake/Instrumentation/query/generated/query-1.json.in
+++ b/Tests/RunCMake/Instrumentation/query/generated/query-1.json.in
@@ -7,6 +7,9 @@
   [
     "postGenerate"
   ],
-  "queries" : [],
+  "options" : [
+    "cdashSubmit",
+    "cdashVerbose"
+  ],
   "version" : 1
 }
diff --git a/Tests/RunCMake/Instrumentation/query/generated/query-2.json.in b/Tests/RunCMake/Instrumentation/query/generated/query-2.json.in
index 58db59f..244abd1 100644
--- a/Tests/RunCMake/Instrumentation/query/generated/query-2.json.in
+++ b/Tests/RunCMake/Instrumentation/query/generated/query-2.json.in
@@ -8,7 +8,7 @@
   [
     "postCMakeBuild"
   ],
-  "queries" :
+  "options" :
   [
     "staticSystemInformation",
     "dynamicSystemInformation"
diff --git a/Tests/RunCMake/Instrumentation/query/hooks-1.json.in b/Tests/RunCMake/Instrumentation/query/hooks-1.json.in
index 31bba86..cfccf14 100644
--- a/Tests/RunCMake/Instrumentation/query/hooks-1.json.in
+++ b/Tests/RunCMake/Instrumentation/query/hooks-1.json.in
@@ -2,5 +2,5 @@
   "version": 1,
   "hooks": ["preCMakeBuild", "postInstall"],
   "callbacks": ["@GET_HOOK@"],
-  "queries": ["staticSystemInformation"]
+  "options": ["staticSystemInformation"]
 }
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyCacheINVALID-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyCacheINVALID-result.txt
diff --git a/Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyCacheINVALID-stderr.txt b/Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyCacheINVALID-stderr.txt
new file mode 100644
index 0000000..30c9184
--- /dev/null
+++ b/Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyCacheINVALID-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error:
+  Unsupported autogen intermediate directory strategy 'INVALID'
+
+
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyEnvINVALID-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyEnvINVALID-result.txt
diff --git a/Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyEnvINVALID-stderr.txt b/Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyEnvINVALID-stderr.txt
new file mode 100644
index 0000000..30c9184
--- /dev/null
+++ b/Tests/RunCMake/IntermediateDirStrategy/AutogenIntDirStrategyEnvINVALID-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error:
+  Unsupported autogen intermediate directory strategy 'INVALID'
+
+
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/IntermediateDirStrategy/CMakeLists.txt b/Tests/RunCMake/IntermediateDirStrategy/CMakeLists.txt
new file mode 100644
index 0000000..5d1e298
--- /dev/null
+++ b/Tests/RunCMake/IntermediateDirStrategy/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.10)
+project(${RunCMake_TEST} NONE)
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyCacheINVALID-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyCacheINVALID-result.txt
diff --git a/Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyCacheINVALID-stderr.txt b/Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyCacheINVALID-stderr.txt
new file mode 100644
index 0000000..86a1e61
--- /dev/null
+++ b/Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyCacheINVALID-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error:
+  Unsupported intermediate directory strategy 'INVALID'
+
+
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyEnvINVALID-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyEnvINVALID-result.txt
diff --git a/Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyEnvINVALID-stderr.txt b/Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyEnvINVALID-stderr.txt
new file mode 100644
index 0000000..86a1e61
--- /dev/null
+++ b/Tests/RunCMake/IntermediateDirStrategy/ObjectIntDirStrategyEnvINVALID-stderr.txt
@@ -0,0 +1,5 @@
+CMake Error:
+  Unsupported intermediate directory strategy 'INVALID'
+
+
+CMake Generate step failed.  Build files cannot be regenerated correctly.
diff --git a/Tests/RunCMake/IntermediateDirStrategy/RunCMakeTest.cmake b/Tests/RunCMake/IntermediateDirStrategy/RunCMakeTest.cmake
new file mode 100644
index 0000000..b719dfd
--- /dev/null
+++ b/Tests/RunCMake/IntermediateDirStrategy/RunCMakeTest.cmake
@@ -0,0 +1,29 @@
+include(RunCMake)
+
+function(run_cmake_intdir_strategy base strategy kind)
+  if (kind STREQUAL "Object")
+    set(varname "CMAKE_INTERMEDIATE_DIR_STRATEGY")
+  elseif (kind STREQUAL "Autogen")
+    set(varname "CMAKE_AUTOGEN_INTERMEDIATE_DIR_STRATEGY")
+  else ()
+    message(FATAL_ERROR "unsupported kind: ${kind}")
+  endif ()
+  unset(ENV{${varname}})
+
+  if (base STREQUAL "IntDirStrategyCache")
+    set(RunCMake_TEST_OPTIONS -D${varname}=${strategy})
+  elseif (base STREQUAL "IntDirStrategyEnv")
+    set(ENV{${varname}} "${strategy}")
+  else ()
+    message(FATAL_ERROR "unsupported base: ${base}")
+  endif ()
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${kind}${base}${strategy}-build)
+  run_cmake(${kind}${base}${strategy})
+endfunction()
+
+foreach (kind IN ITEMS Object Autogen)
+  foreach (strategy IN ITEMS INVALID FULL SHORT)
+    run_cmake_intdir_strategy(IntDirStrategyCache ${strategy} ${kind})
+    run_cmake_intdir_strategy(IntDirStrategyEnv ${strategy} ${kind})
+  endforeach ()
+endforeach ()
diff --git a/Tests/RunCMake/Make/GNUMakeJobServerAware.cmake b/Tests/RunCMake/Make/GNUMakeJobServerAware.cmake
index d92e842..997cf8e 100644
--- a/Tests/RunCMake/Make/GNUMakeJobServerAware.cmake
+++ b/Tests/RunCMake/Make/GNUMakeJobServerAware.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 # Test JOB_SERVER_AWARE with custom commands
 add_custom_command(
   OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/missing"
diff --git a/Tests/RunCMake/Make/RunCMakeTest.cmake b/Tests/RunCMake/Make/RunCMakeTest.cmake
index 9673329..2830199 100644
--- a/Tests/RunCMake/Make/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Make/RunCMakeTest.cmake
@@ -39,6 +39,29 @@
 endfunction()
 run_VerboseBuild()
 
+function(run_VerboseBuildShort)
+  run_cmake(VerboseBuildShort)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VerboseBuildShort-build)
+  if(RunCMake_GENERATOR STREQUAL "Watcom WMake")
+    # wmake does not actually show the verbose output.
+    set(RunCMake-stdout-file VerboseBuildShort-build-watcom-stdout.txt)
+  endif()
+  run_cmake_command(VerboseBuildShort-build ${CMAKE_COMMAND} --build . -v --clean-first)
+  unset(RunCMake-stdout-file)
+  set(_backup_lang "$ENV{LANG}")
+  set(_backup_lc_Messages "$ENV{LC_MESSAGES}")
+  if(MAKE_IS_GNU)
+    set(RunCMake-stdout-file VerboseBuildShort-nowork-gnu-stdout.txt)
+    set(ENV{LANG} "C")
+    set(ENV{LC_MESSAGES} "C")
+  endif()
+  run_cmake_command(VerboseBuildShort-nowork ${CMAKE_COMMAND} --build . --verbose)
+  set(ENV{LANG} "${_backup_lang}")
+  set(ENV{LC_MESSAGES} "${_backup_lc_messages}")
+endfunction()
+run_VerboseBuildShort()
+
 run_cmake(IncludeRegexSubdir)
 
 function(run_MakefileConflict)
diff --git a/Tests/RunCMake/Make/VerboseBuild.cmake b/Tests/RunCMake/Make/VerboseBuild.cmake
index 70a971d..ec76816 100644
--- a/Tests/RunCMake/Make/VerboseBuild.cmake
+++ b/Tests/RunCMake/Make/VerboseBuild.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 # Make sure compile command is not hidden in a temp file.
diff --git a/Tests/RunCMake/Make/VerboseBuildShort-build-stdout.txt b/Tests/RunCMake/Make/VerboseBuildShort-build-stdout.txt
new file mode 100644
index 0000000..447d812
--- /dev/null
+++ b/Tests/RunCMake/Make/VerboseBuildShort-build-stdout.txt
@@ -0,0 +1 @@
+DEFINE_FOR_VERBOSE_DETECTION.*.o[\\/]75d5d702[\\/]4efa03e1
diff --git a/Tests/RunCMake/Make/VerboseBuildShort-build-watcom-stdout.txt b/Tests/RunCMake/Make/VerboseBuildShort-build-watcom-stdout.txt
new file mode 100644
index 0000000..ce5c2a9
--- /dev/null
+++ b/Tests/RunCMake/Make/VerboseBuildShort-build-watcom-stdout.txt
@@ -0,0 +1 @@
+Building C object _o/75d5d702/4efa03e1.obj
diff --git a/Tests/RunCMake/Make/VerboseBuildShort-nowork-gnu-stdout.txt b/Tests/RunCMake/Make/VerboseBuildShort-nowork-gnu-stdout.txt
new file mode 100644
index 0000000..3e65cd9
--- /dev/null
+++ b/Tests/RunCMake/Make/VerboseBuildShort-nowork-gnu-stdout.txt
@@ -0,0 +1 @@
+.*Nothing to be done for.*hello.*
diff --git a/Tests/RunCMake/Make/VerboseBuildShort.cmake b/Tests/RunCMake/Make/VerboseBuildShort.cmake
new file mode 100644
index 0000000..2983e7c
--- /dev/null
+++ b/Tests/RunCMake/Make/VerboseBuildShort.cmake
@@ -0,0 +1,10 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(C)
+
+# Make sure compile command is not hidden in a temp file.
+string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}")
+string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}")
+
+add_executable(hello hello.c)
+target_compile_definitions(hello PRIVATE "DEFINE_FOR_VERBOSE_DETECTION")
diff --git a/Tests/RunCMake/Ninja/LooseObjectDepends.cmake b/Tests/RunCMake/Ninja/LooseObjectDepends.cmake
index 90f8249..83911e1 100644
--- a/Tests/RunCMake/Ninja/LooseObjectDepends.cmake
+++ b/Tests/RunCMake/Ninja/LooseObjectDepends.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 add_custom_command(
diff --git a/Tests/RunCMake/Ninja/LooseObjectDependsShort.cmake b/Tests/RunCMake/Ninja/LooseObjectDependsShort.cmake
new file mode 100644
index 0000000..21252dc
--- /dev/null
+++ b/Tests/RunCMake/Ninja/LooseObjectDependsShort.cmake
@@ -0,0 +1,27 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(C)
+
+add_custom_command(
+  OUTPUT  "${CMAKE_CURRENT_BINARY_DIR}/command.h"
+  COMMAND "${CMAKE_COMMAND}" -E touch
+          "${CMAKE_CURRENT_BINARY_DIR}/command.h"
+          COMMENT "Creating command.h")
+add_custom_target(create-command.h
+  DEPENDS
+    "${CMAKE_CURRENT_BINARY_DIR}/command.h")
+
+add_custom_target(create-target.h
+  BYPRODUCTS  "${CMAKE_CURRENT_BINARY_DIR}/target.h"
+  COMMAND "${CMAKE_COMMAND}" -E touch
+          "${CMAKE_CURRENT_BINARY_DIR}/target.h"
+  COMMENT "Creating target.h")
+
+add_library(dep SHARED dep.c)
+add_dependencies(dep create-command.h create-target.h)
+target_include_directories(dep
+  PUBLIC
+    "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_library(top top.c)
+target_link_libraries(top PRIVATE dep)
diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
index cbf7f26..81606cb 100644
--- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake
@@ -83,6 +83,16 @@
 endfunction()
 run_VerboseBuild()
 
+function(run_VerboseBuildShort)
+  run_cmake(VerboseBuildShort)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/VerboseBuildShort-build)
+  set(RunCMake_TEST_OUTPUT_MERGE 1)
+  run_cmake_command(VerboseBuildShort-build ${CMAKE_COMMAND} --build . -v --clean-first)
+  run_cmake_command(VerboseBuildShort-nowork ${CMAKE_COMMAND} --build . --verbose)
+endfunction()
+run_VerboseBuildShort()
+
 function(run_CMP0058 case)
   # Use a single build tree for a few tests without cleaning.
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0058-${case}-build)
@@ -100,6 +110,7 @@
 run_cmake_with_options(CustomCommandDepfileAsOutput -DCMAKE_BUILD_TYPE=Debug)
 run_cmake_with_options(CustomCommandDepfileAsByproduct -DCMAKE_BUILD_TYPE=Debug)
 run_cmake(CustomCommandJobPool)
+run_cmake(SourceFileJobPool)
 run_cmake(JobPoolUsesTerminal)
 
 run_cmake(RspFileC)
@@ -194,6 +205,23 @@
 endfunction ()
 run_LooseObjectDepends()
 
+function (run_LooseObjectDependsShort)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/LooseObjectDependsShort-build)
+  run_cmake(LooseObjectDependsShort)
+  run_ninja("${RunCMake_TEST_BINARY_DIR}" ".o/e86fd702/b1363cd8${CMAKE_C_OUTPUT_EXTENSION}")
+  if (EXISTS "${RunCMake_TEST_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}dep${CMAKE_SHARED_LIBRARY_SUFFIX}")
+    message(FATAL_ERROR
+      "The `dep` library was created when requesting an object file to be "
+      "built; this should no longer be necessary.")
+  endif ()
+  if (EXISTS "${RunCMake_TEST_BINARY_DIR}/.o/600bd702/d56215${CMAKE_C_OUTPUT_EXTENSION}")
+    message(FATAL_ERROR
+      "The `dep.c` object file was created when requesting an object file to "
+      "be built; this should no longer be necessary.")
+  endif ()
+endfunction ()
+run_LooseObjectDependsShort()
+
 function (run_CustomCommandExplictDepends)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CustomCommandExplicitDepends-build)
   run_cmake(CustomCommandExplicitDepends)
@@ -424,3 +452,5 @@
 endif()
 
 run_cmake(LINK_OPTIONSWithNewlines)
+
+run_cmake(StaticLibShort)
diff --git a/Tests/RunCMake/Ninja/SourceFileJobPool-check.cmake b/Tests/RunCMake/Ninja/SourceFileJobPool-check.cmake
new file mode 100644
index 0000000..e719522
--- /dev/null
+++ b/Tests/RunCMake/Ninja/SourceFileJobPool-check.cmake
@@ -0,0 +1,14 @@
+set(log "${RunCMake_BINARY_DIR}/SourceFileJobPool-build/build.ninja")
+file(READ "${log}" build_file)
+if(NOT "${build_file}" MATCHES "pool = source_file_compile_pool")
+  string(CONCAT RunCMake_TEST_FAILED "Log file:\n ${log}\n" "does not have expected line: pool = source_file_compile_pool")
+endif()
+if(NOT "${build_file}" MATCHES "pool = target_link_pool")
+  string(CONCAT RunCMake_TEST_FAILED "Log file:\n ${log}\n" "does not have expected line: pool = target_link_pool")
+endif()
+# Even though `target_compile_pool` was defined as the target's compile jobs pool, since the only sourcefile
+# of the target overrides it with `source_file_compile_pool` pool, the target compile job pool should not
+# exist in the generated Ninja file.
+if("${build_file}" MATCHES "pool = target_compile_pool")
+  string(CONCAT RunCMake_TEST_FAILED "Log file:\n ${log}\n" "have unexpected line: pool = target_compile_pool")
+endif()
diff --git a/Tests/RunCMake/Ninja/SourceFileJobPool.cmake b/Tests/RunCMake/Ninja/SourceFileJobPool.cmake
new file mode 100644
index 0000000..ee9e79f
--- /dev/null
+++ b/Tests/RunCMake/Ninja/SourceFileJobPool.cmake
@@ -0,0 +1,11 @@
+set_property(GLOBAL PROPERTY JOB_POOLS source_file_compile_pool=2 target_compile_pool=4 target_link_pool=1)
+
+enable_language(C)
+
+set_property(SOURCE hello.c PROPERTY JOB_POOL_COMPILE "source_file_compile_pool")
+
+add_executable(hello hello.c)
+set_property(TARGET hello PROPERTY JOB_POOL_COMPILE "target_compile_pool")
+set_property(TARGET hello PROPERTY JOB_POOL_LINK "target_link_pool")
+
+include(CheckNoPrefixSubDir.cmake)
diff --git a/Tests/RunCMake/Ninja/StaticLibShort-build-stdout.txt b/Tests/RunCMake/Ninja/StaticLibShort-build-stdout.txt
new file mode 100644
index 0000000..da52e4ec
--- /dev/null
+++ b/Tests/RunCMake/Ninja/StaticLibShort-build-stdout.txt
@@ -0,0 +1 @@
+.*.o.75d5d702.cf59cf\.o.*
diff --git a/Tests/RunCMake/Ninja/StaticLibShort.cmake b/Tests/RunCMake/Ninja/StaticLibShort.cmake
new file mode 100644
index 0000000..4b9a094
--- /dev/null
+++ b/Tests/RunCMake/Ninja/StaticLibShort.cmake
@@ -0,0 +1,7 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(C)
+add_library(greeting STATIC greeting.c)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+add_executable(hello hello_with_greeting.c)
+target_link_libraries(hello greeting)
diff --git a/Tests/RunCMake/Ninja/VerboseBuild.cmake b/Tests/RunCMake/Ninja/VerboseBuild.cmake
index 424e54e..cc3d9d0 100644
--- a/Tests/RunCMake/Ninja/VerboseBuild.cmake
+++ b/Tests/RunCMake/Ninja/VerboseBuild.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 add_executable(hello hello.c)
 target_compile_definitions(hello PRIVATE "DEFINE_FOR_VERBOSE_DETECTION")
diff --git a/Tests/RunCMake/Ninja/VerboseBuildShort-build-stdout.txt b/Tests/RunCMake/Ninja/VerboseBuildShort-build-stdout.txt
new file mode 100644
index 0000000..5fd67d6
--- /dev/null
+++ b/Tests/RunCMake/Ninja/VerboseBuildShort-build-stdout.txt
@@ -0,0 +1 @@
+DEFINE_FOR_VERBOSE_DETECTION.*75d5d702.4efa03e1.o
diff --git a/Tests/RunCMake/Ninja/VerboseBuildShort-nowork-stdout.txt b/Tests/RunCMake/Ninja/VerboseBuildShort-nowork-stdout.txt
new file mode 100644
index 0000000..40b4527
--- /dev/null
+++ b/Tests/RunCMake/Ninja/VerboseBuildShort-nowork-stdout.txt
@@ -0,0 +1 @@
+ninja: no work to do
diff --git a/Tests/RunCMake/Ninja/VerboseBuildShort.cmake b/Tests/RunCMake/Ninja/VerboseBuildShort.cmake
new file mode 100644
index 0000000..914d01e
--- /dev/null
+++ b/Tests/RunCMake/Ninja/VerboseBuildShort.cmake
@@ -0,0 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(C)
+add_executable(hello hello.c)
+target_compile_definitions(hello PRIVATE "DEFINE_FOR_VERBOSE_DETECTION")
diff --git a/Tests/RunCMake/NinjaMultiConfig/CompileCommands.cmake b/Tests/RunCMake/NinjaMultiConfig/CompileCommands.cmake
index fc44d5a..eeb3c9a 100644
--- a/Tests/RunCMake/NinjaMultiConfig/CompileCommands.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/CompileCommands.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 add_executable(exe main.c)
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake
index 2de5a3a..ab3e7cf 100644
--- a/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandOutputGenex.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 add_executable(echo echo.c)
diff --git a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets.cmake b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets.cmake
index b7e4aea..00feb9e 100644
--- a/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/CustomCommandsAndTargets.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 file(REMOVE "${CMAKE_BINARY_DIR}/target_files_custom.cmake")
diff --git a/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake
index 52f84ea..46d8aad 100644
--- a/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/ExcludeFromAll.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 set(CMAKE_CONFIGURATION_TYPES "Release;Debug" CACHE STRING "")
diff --git a/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation.cmake b/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation.cmake
index abef3c8..d0b1180 100644
--- a/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation.cmake
+++ b/Tests/RunCMake/NinjaMultiConfig/PostfixAndLocation.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 set(CMAKE_DEBUG_POSTFIX "_debug")
diff --git a/Tests/RunCMake/NinjaPrivateDeps/CMP0154-common.cmake b/Tests/RunCMake/NinjaPrivateDeps/CMP0154-common.cmake
index a9e6d20..8819f32 100644
--- a/Tests/RunCMake/NinjaPrivateDeps/CMP0154-common.cmake
+++ b/Tests/RunCMake/NinjaPrivateDeps/CMP0154-common.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 
 function(copy_file file dest)
diff --git a/Tests/RunCMake/ObjectLibrary/Dependencies.cmake b/Tests/RunCMake/ObjectLibrary/Dependencies.cmake
index 6ddf545..2ad2f29 100644
--- a/Tests/RunCMake/ObjectLibrary/Dependencies.cmake
+++ b/Tests/RunCMake/ObjectLibrary/Dependencies.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 add_library(myobj OBJECT ${CMAKE_BINARY_DIR}/depends_obj.c)
 add_library(mylib STATIC $<TARGET_OBJECTS:myobj> depends_lib.c)
 add_executable(myexe depends_main.c)
diff --git a/Tests/RunCMake/ObjectLibrary/DependenciesShort.cmake b/Tests/RunCMake/ObjectLibrary/DependenciesShort.cmake
new file mode 100644
index 0000000..7380e8d
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/DependenciesShort.cmake
@@ -0,0 +1,9 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+add_library(myobj OBJECT ${CMAKE_BINARY_DIR}/depends_obj.c)
+add_library(mylib STATIC $<TARGET_OBJECTS:myobj> depends_lib.c)
+add_executable(myexe depends_main.c)
+target_link_libraries(myexe mylib)
+
+enable_testing()
+add_test(NAME myexe COMMAND $<TARGET_FILE:myexe>)
diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
index 0e31b78..33aebe9 100644
--- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
@@ -67,9 +67,8 @@
 run_cmake(PreBuild)
 run_cmake(PreLink)
 
-
-function(run_Dependencies)
-  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Dependencies-build)
+function(run_Dependencies suffix)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Dependencies${suffix}-build)
   set(RunCMake_TEST_NO_CLEAN 1)
 
   file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
@@ -82,13 +81,16 @@
     set(fs_delay 1.125)
   endif()
 
-  run_cmake_command(Dependencies-build ${CMAKE_COMMAND} -E copy ${RunCMake_SOURCE_DIR}/depends_obj1.c ${RunCMake_TEST_BINARY_DIR}/depends_obj.c)
-  run_cmake(Dependencies)
-  run_cmake_command(Dependencies-build ${CMAKE_COMMAND} --build . --config Debug)
-  run_cmake_command(Dependencies-build ${CMAKE_COMMAND} -E sleep ${fs_delay})
-  run_cmake_command(Dependencies-build ${CMAKE_COMMAND} -E copy ${RunCMake_SOURCE_DIR}/depends_obj0.c ${RunCMake_TEST_BINARY_DIR}/depends_obj.c)
-  run_cmake_command(Dependencies-build ${CMAKE_COMMAND} --build . --config Debug)
-  run_cmake_command(Dependencies-build ${CMAKE_CTEST_COMMAND} -C Debug -V)
+  run_cmake_command(Dependencies${suffix}-build ${CMAKE_COMMAND} -E copy ${RunCMake_SOURCE_DIR}/depends_obj1.c ${RunCMake_TEST_BINARY_DIR}/depends_obj.c)
+  run_cmake_with_options(Dependencies${suffix})
+  run_cmake_command(Dependencies${suffix}-build ${CMAKE_COMMAND} --build . --config Debug)
+  run_cmake_command(Dependencies${suffix}-build ${CMAKE_COMMAND} -E sleep ${fs_delay})
+  run_cmake_command(Dependencies${suffix}-build ${CMAKE_COMMAND} -E copy ${RunCMake_SOURCE_DIR}/depends_obj0.c ${RunCMake_TEST_BINARY_DIR}/depends_obj.c)
+  run_cmake_command(Dependencies${suffix}-build ${CMAKE_COMMAND} --build . --config Debug)
+  run_cmake_command(Dependencies${suffix}-build ${CMAKE_CTEST_COMMAND} -C Debug -V)
 endfunction()
 
-run_Dependencies()
+run_Dependencies("")
+if (CMAKE_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+  run_Dependencies(Short)
+endif ()
diff --git a/Tests/RunCMake/PrecompileHeaders/CXXnotC.cmake b/Tests/RunCMake/PrecompileHeaders/CXXnotC.cmake
index 9ec1b36..1f5d633 100644
--- a/Tests/RunCMake/PrecompileHeaders/CXXnotC.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/CXXnotC.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_language(CXX)
 
diff --git a/Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake b/Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake
index 18b09c1..bd39193 100644
--- a/Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/DisabledPch.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 add_library(foo foo.c)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake b/Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake
index 039a546..19c875e 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchDebugGenex.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 add_library(foo foo.c)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchDebugGenexShort-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchDebugGenexShort-check.cmake
new file mode 100644
index 0000000..2218297
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchDebugGenexShort-check.cmake
@@ -0,0 +1,17 @@
+if (NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  return()
+endif()
+
+set(foo_pch_header "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/4bcad702/Debug/cmake_pch.h")
+
+if (NOT EXISTS ${foo_pch_header})
+  set(RunCMake_TEST_FAILED "Generated foo pch header ${foo_pch_header} does not exist")
+  return()
+endif()
+
+file(STRINGS ${foo_pch_header} foo_pch_header_strings)
+
+if (NOT foo_pch_header_strings MATCHES ";#include \"[^\"]*PrecompileHeaders/include/foo.h\";#include <stdio.h>(;|$)")
+  set(RunCMake_TEST_FAILED "Generated foo pch header\n  ${foo_pch_header}\nhas bad content:\n  ${foo_pch_header_strings}")
+  return()
+endif()
diff --git a/Tests/RunCMake/PrecompileHeaders/PchDebugGenexShort.cmake b/Tests/RunCMake/PrecompileHeaders/PchDebugGenexShort.cmake
new file mode 100644
index 0000000..f648740
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchDebugGenexShort.cmake
@@ -0,0 +1,10 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(C)
+
+add_library(foo foo.c)
+target_include_directories(foo PUBLIC include)
+target_precompile_headers(foo PUBLIC
+  "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/include/foo.h>"
+  <stdio.h>
+)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchIncludedAllLanguages.cmake b/Tests/RunCMake/PrecompileHeaders/PchIncludedAllLanguages.cmake
index eef189a..160a4d5 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchIncludedAllLanguages.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchIncludedAllLanguages.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_language(CXX)
 
diff --git a/Tests/RunCMake/PrecompileHeaders/PchIncludedOneLanguage.cmake b/Tests/RunCMake/PrecompileHeaders/PchIncludedOneLanguage.cmake
index 6c5e89d..7a16147 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchIncludedOneLanguage.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchIncludedOneLanguage.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_language(CXX)
 
diff --git a/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake b/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake
index c031660..aebabc3 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchInterface.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 add_library(foo foo.c)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchInterfaceShort-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchInterfaceShort-check.cmake
new file mode 100644
index 0000000..7f8e8b7
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchInterfaceShort-check.cmake
@@ -0,0 +1,9 @@
+set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/.o/ff32d702/cmake_pch.h")
+if (RunCMake_GENERATOR_IS_MULTI_CONFIG)
+  set(foobar_pch_header "${RunCMake_TEST_BINARY_DIR}/.o/ff32d702/Debug/cmake_pch.h")
+endif()
+
+if (NOT EXISTS ${foobar_pch_header})
+  set(RunCMake_TEST_FAILED "Generated foobar pch header ${foobar_pch_header} does not exist")
+  return()
+endif()
diff --git a/Tests/RunCMake/PrecompileHeaders/PchInterfaceShort.cmake b/Tests/RunCMake/PrecompileHeaders/PchInterfaceShort.cmake
new file mode 100644
index 0000000..deff6c3
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchInterfaceShort.cmake
@@ -0,0 +1,22 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(C)
+
+add_library(foo foo.c)
+target_include_directories(foo PUBLIC include)
+target_precompile_headers(foo PUBLIC
+  include/foo.h
+  \"foo2.h\"
+  <stdio.h>
+  \"string.h\"
+)
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+  set_property(SOURCE foo.c APPEND PROPERTY COMPILE_OPTIONS "-WX-")
+endif()
+
+add_library(bar INTERFACE)
+target_include_directories(bar INTERFACE include)
+target_precompile_headers(bar INTERFACE include/bar.h)
+
+add_executable(foobar foobar.c)
+target_link_libraries(foobar foo bar)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchInterfaceUnity.cmake b/Tests/RunCMake/PrecompileHeaders/PchInterfaceUnity.cmake
index 59c2523..2e40509 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchInterfaceUnity.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchInterfaceUnity.cmake
@@ -1,2 +1,4 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 set(CMAKE_UNITY_BUILD 1)
 include(PchInterface.cmake)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchLibObjLibExe.cmake b/Tests/RunCMake/PrecompileHeaders/PchLibObjLibExe.cmake
index ad8a328..6fc0797 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchLibObjLibExe.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchLibObjLibExe.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(CXX)
 
 foreach(i 1 2 3)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake
index d8abf8e..9993778 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchMultilanguage.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_language(CXX)
 
diff --git a/Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue.cmake b/Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue.cmake
index 988c4c6..60c1d04 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchPrologueEpilogue.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_language(CXX)
 
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseAppend-build-stderr.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseAppend-build-stderr.txt
new file mode 100644
index 0000000..005f3a0
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseAppend-build-stderr.txt
@@ -0,0 +1,2 @@
+((Classic Intel)?Warning #672: the command line options do not match those used[^
+]*)?
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseAppend.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseAppend.cmake
new file mode 100644
index 0000000..eb324fc
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseAppend.cmake
@@ -0,0 +1,60 @@
+enable_language(CXX)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+  add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/pch.cxx [=[
+void nothing()
+{
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/string.hxx [=[
+#include <string.h>
+
+namespace std {
+  struct string
+  {
+    char storage[20];
+
+    string(const char* s) {
+      strcpy(storage, s);
+    }
+
+    const char* c_str() const {
+      return storage;
+    }
+  };
+}
+]=])
+
+add_library(pch-generator ${CMAKE_BINARY_DIR}/pch.cxx)
+target_precompile_headers(pch-generator PRIVATE ${CMAKE_BINARY_DIR}/string.hxx)
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.cxx [=[
+#include "message.hxx"
+
+#ifndef HAVE_PCH_SUPPORT
+  #include "string.hxx"
+#endif
+
+const char* message()
+{
+  static std::string greeting("hi there");
+  return greeting.c_str();
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.hxx [=[
+const char* message();
+]=])
+
+add_library(reuse_append ${CMAKE_BINARY_DIR}/message.cxx)
+target_include_directories(reuse_append PRIVATE ${CMAKE_BINARY_DIR})
+set_property(TARGET reuse_append PROPERTY PRECOMPILE_HEADERS_REUSE_FROM "pch-")
+set_property(TARGET reuse_append APPEND_STRING PROPERTY PRECOMPILE_HEADERS_REUSE_FROM "generator")
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseConsistency-build-stderr.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseConsistency-build-stderr.txt
new file mode 100644
index 0000000..005f3a0
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseConsistency-build-stderr.txt
@@ -0,0 +1,2 @@
+((Classic Intel)?Warning #672: the command line options do not match those used[^
+]*)?
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseConsistency.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseConsistency.cmake
new file mode 100644
index 0000000..f1f07ce
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseConsistency.cmake
@@ -0,0 +1,79 @@
+enable_language(CXX)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+  add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/pch.cxx [=[
+void nothing()
+{
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/string.hxx [=[
+#include <string.h>
+
+namespace std {
+  struct string
+  {
+    char storage[20];
+
+    string(const char* s) {
+      strcpy(storage, s);
+    }
+
+    const char* c_str() const {
+      return storage;
+    }
+  };
+}
+]=])
+
+add_library(pch-generator ${CMAKE_BINARY_DIR}/pch.cxx)
+target_precompile_headers(pch-generator PRIVATE ${CMAKE_BINARY_DIR}/string.hxx)
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.cxx [=[
+#include "message.hxx"
+
+#ifndef HAVE_PCH_SUPPORT
+  #include "string.hxx"
+#endif
+
+const char* message()
+{
+  static std::string greeting("hi there");
+  return greeting.c_str();
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.hxx [=[
+const char* message();
+]=])
+
+add_library(pch_before_reuse_pch ${CMAKE_BINARY_DIR}/message.cxx)
+target_precompile_headers(pch_before_reuse_pch PRIVATE "${CMAKE_BINARY_DIR}/string.hxx")
+target_precompile_headers(pch_before_reuse_pch REUSE_FROM pch-generator)
+set_property(TARGET pch_before_reuse_pch PROPERTY PRECOMPILE_HEADERS_REUSE_FROM)
+target_include_directories(pch_before_reuse_pch PRIVATE ${CMAKE_BINARY_DIR})
+
+add_library(pch_before_reuse_reuse ${CMAKE_BINARY_DIR}/message.cxx)
+target_precompile_headers(pch_before_reuse_reuse PRIVATE "${CMAKE_BINARY_DIR}/string.hxx")
+target_precompile_headers(pch_before_reuse_reuse REUSE_FROM pch-generator)
+set_property(TARGET pch_before_reuse_reuse PROPERTY PRECOMPILE_HEADERS "")
+target_include_directories(pch_before_reuse_reuse PRIVATE ${CMAKE_BINARY_DIR})
+
+add_library(reuse_before_pch_pch ${CMAKE_BINARY_DIR}/message.cxx)
+target_precompile_headers(reuse_before_pch_pch REUSE_FROM pch-generator)
+target_precompile_headers(reuse_before_pch_pch PRIVATE "${CMAKE_BINARY_DIR}/string.hxx")
+set_property(TARGET reuse_before_pch_pch PROPERTY PRECOMPILE_HEADERS_REUSE_FROM)
+target_include_directories(reuse_before_pch_pch PRIVATE ${CMAKE_BINARY_DIR})
+
+add_library(reuse_before_pch_reuse ${CMAKE_BINARY_DIR}/message.cxx)
+target_precompile_headers(reuse_before_pch_reuse REUSE_FROM pch-generator)
+target_precompile_headers(reuse_before_pch_reuse PRIVATE "${CMAKE_BINARY_DIR}/string.hxx")
+set_property(TARGET reuse_before_pch_reuse PROPERTY PRECOMPILE_HEADERS "")
+target_include_directories(reuse_before_pch_reuse PRIVATE ${CMAKE_BINARY_DIR})
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseDeclarationOrder-build-stderr.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseDeclarationOrder-build-stderr.txt
new file mode 100644
index 0000000..005f3a0
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseDeclarationOrder-build-stderr.txt
@@ -0,0 +1,2 @@
+((Classic Intel)?Warning #672: the command line options do not match those used[^
+]*)?
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseDeclarationOrder.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseDeclarationOrder.cmake
new file mode 100644
index 0000000..972cae2
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseDeclarationOrder.cmake
@@ -0,0 +1,59 @@
+enable_language(CXX)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+  add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.cxx [=[
+#include "message.hxx"
+
+#ifndef HAVE_PCH_SUPPORT
+  #include "string.hxx"
+#endif
+
+const char* message()
+{
+  static std::string greeting("hi there");
+  return greeting.c_str();
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.hxx [=[
+const char* message();
+]=])
+
+add_library(reuse_decl_order ${CMAKE_BINARY_DIR}/message.cxx)
+target_precompile_headers(reuse_decl_order REUSE_FROM pch-generator)
+target_include_directories(reuse_decl_order PRIVATE ${CMAKE_BINARY_DIR})
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/pch.cxx [=[
+void nothing()
+{
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/string.hxx [=[
+#include <string.h>
+
+namespace std {
+  struct string
+  {
+    char storage[20];
+
+    string(const char* s) {
+      strcpy(storage, s);
+    }
+
+    const char* c_str() const {
+      return storage;
+    }
+  };
+}
+]=])
+
+add_library(pch-generator ${CMAKE_BINARY_DIR}/pch.cxx)
+target_precompile_headers(pch-generator PRIVATE ${CMAKE_BINARY_DIR}/string.hxx)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-NEW-empty.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-NEW-empty.cmake
index 41c7d22..9b88183 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-NEW-empty.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-NEW-empty.cmake
@@ -1,4 +1,4 @@
 cmake_policy(SET CMP0141 NEW)
 set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "")
 string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -Zi")
-include(PchReuseFrom-common.cmake)
+include(PchReuseFrom-CMP0141-common.cmake)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-NEW.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-NEW.cmake
index daf7a38..b724904 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-NEW.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-NEW.cmake
@@ -1,2 +1,2 @@
 cmake_policy(SET CMP0141 NEW)
-include(PchReuseFrom-common.cmake)
+include(PchReuseFrom-CMP0141-common.cmake)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-OLD.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-OLD.cmake
index 9586887..1d676fc 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-OLD.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-OLD.cmake
@@ -1,2 +1,2 @@
 cmake_policy(SET CMP0141 OLD)
-include(PchReuseFrom-common.cmake)
+include(PchReuseFrom-CMP0141-common.cmake)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-common.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-common.cmake
similarity index 92%
rename from Tests/RunCMake/PrecompileHeaders/PchReuseFrom-common.cmake
rename to Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-common.cmake
index 8d5e945..ad9d2be 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-common.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFrom-CMP0141-common.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 if(CMAKE_C_COMPILE_OPTIONS_USE_PCH)
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseFromCycle-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/PrecompileHeaders/PchReuseFromCycle-result.txt
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromCycle-stderr.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseFromCycle-stderr.txt
new file mode 100644
index 0000000..febdb0b
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromCycle-stderr.txt
@@ -0,0 +1,2 @@
+CMake Error in CMakeLists.txt:
+  Circular PCH reuse target involving 'first'
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromCycle.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromCycle.cmake
new file mode 100644
index 0000000..3a2d168
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromCycle.cmake
@@ -0,0 +1,10 @@
+enable_language(C)
+
+add_library(first foo.c)
+target_precompile_headers(first REUSE_FROM third)
+
+add_library(second foo.c)
+target_precompile_headers(second REUSE_FROM first)
+
+add_library(third foo.c)
+target_precompile_headers(third REUSE_FROM second)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps-build-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps-build-check.cmake
new file mode 100644
index 0000000..cc571a2
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps-build-check.cmake
@@ -0,0 +1,19 @@
+if(MSVC OR (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_SIMULATE_ID STREQUAL "MSVC"))
+  find_file(pdb_file
+    NAMES NOT_USED.pdb
+    PATHS "${RunCMake_TEST_BINARY_DIR}"
+    PATH_SUFFIXES NOT_USED NOT_USED_DEBUG)
+  if (EXISTS "${pdb_file}")
+    list(APPEND RunCMake_TEST_FAILED
+      "PDB file was created from properties meant to be ignored")
+  endif ()
+
+  if (EXISTS "${RunCMake_TEST_BINARY_DIR}/mycustomdir")
+    list(APPEND RunCMake_TEST_FAILED
+      "PDB output directory ('mycustomdir') was created (should have used debug variant)")
+  endif ()
+  if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/mycustomdir_debug")
+    list(APPEND RunCMake_TEST_FAILED
+      "PDB output directory ('mycustomdir_debug') was not created (separate PDBs required)")
+  endif ()
+endif ()
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps-build-stderr.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps-build-stderr.txt
new file mode 100644
index 0000000..005f3a0
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps-build-stderr.txt
@@ -0,0 +1,2 @@
+((Classic Intel)?Warning #672: the command line options do not match those used[^
+]*)?
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps.cmake
new file mode 100644
index 0000000..66dbf50
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromIgnoreOwnProps.cmake
@@ -0,0 +1,66 @@
+enable_language(CXX)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+  add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/pch.cxx [=[
+void nothing()
+{
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/string.hxx [=[
+#include <string.h>
+
+namespace std {
+  struct string
+  {
+    char storage[20];
+
+    string(const char* s) {
+      strcpy(storage, s);
+    }
+
+    const char* c_str() const {
+      return storage;
+    }
+  };
+}
+]=])
+
+add_library(pch-generator ${CMAKE_BINARY_DIR}/pch.cxx)
+target_precompile_headers(pch-generator PRIVATE ${CMAKE_BINARY_DIR}/string.hxx)
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.cxx [=[
+#include "message.hxx"
+
+#ifndef HAVE_PCH_SUPPORT
+  #include "string.hxx"
+#endif
+
+const char* message()
+{
+  static std::string greeting("hi there");
+  return greeting.c_str();
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.hxx [=[
+const char* message();
+]=])
+
+add_library(ignored_props ${CMAKE_BINARY_DIR}/message.cxx)
+target_precompile_headers(ignored_props REUSE_FROM pch-generator)
+target_include_directories(ignored_props PRIVATE ${CMAKE_BINARY_DIR})
+
+set_target_properties(ignored_props
+  PROPERTIES
+    COMPILE_PDB_NAME "NOT_USED"
+    COMPILE_PDB_NAME_DEBUG "NOT_USED_DEBUG"
+    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/mycustomdir"
+    COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/mycustomdir_debug")
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromObjLib.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromObjLib.cmake
index 510877f..6257fdc 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchReuseFromObjLib.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromObjLib.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_language(CXX)
 
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromPrefixed.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromPrefixed.cmake
index 14703e3..22ee46b 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchReuseFromPrefixed.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromPrefixed.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 if(CMAKE_C_COMPILE_OPTIONS_USE_PCH)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromSubdir.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromSubdir.cmake
index fefb4ee..76be41f 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchReuseFromSubdir.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromSubdir.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 add_library(empty empty.c)
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps-build-check.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps-build-check.cmake
new file mode 100644
index 0000000..1cb8b56
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps-build-check.cmake
@@ -0,0 +1,16 @@
+if(MSVC)
+  find_file(pdb_file
+    NAMES custom-post.pdb custom-post-debug.pdb
+    PATHS "${RunCMake_TEST_BINARY_DIR}"
+    PATH_SUFFIXES custom custom-debug)
+  if (NOT EXISTS "${pdb_file}")
+    list(APPEND RunCMake_TEST_FAILED
+      "PDB file was not created from properties updated after reuse link")
+  endif ()
+
+  if (NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/custom" AND
+      NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/custom-debug")
+    list(APPEND RunCMake_TEST_FAILED
+      "Updated PDB output directory ('custom' or 'custom-debug') was not created")
+  endif ()
+endif ()
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps-build-stderr.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps-build-stderr.txt
new file mode 100644
index 0000000..005f3a0
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps-build-stderr.txt
@@ -0,0 +1,2 @@
+((Classic Intel)?Warning #672: the command line options do not match those used[^
+]*)?
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps.cmake
new file mode 100644
index 0000000..a7bd978
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseFromUseUpdatedProps.cmake
@@ -0,0 +1,66 @@
+enable_language(CXX)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+  add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/pch.cxx [=[
+void nothing()
+{
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/string.hxx [=[
+#include <string.h>
+
+namespace std {
+  struct string
+  {
+    char storage[20];
+
+    string(const char* s) {
+      strcpy(storage, s);
+    }
+
+    const char* c_str() const {
+      return storage;
+    }
+  };
+}
+]=])
+
+add_library(pch-generator ${CMAKE_BINARY_DIR}/pch.cxx)
+target_precompile_headers(pch-generator PRIVATE ${CMAKE_BINARY_DIR}/string.hxx)
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.cxx [=[
+#include "message.hxx"
+
+#ifndef HAVE_PCH_SUPPORT
+  #include "string.hxx"
+#endif
+
+const char* message()
+{
+  static std::string greeting("hi there");
+  return greeting.c_str();
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.hxx [=[
+const char* message();
+]=])
+
+add_library(updated_props ${CMAKE_BINARY_DIR}/message.cxx)
+target_precompile_headers(updated_props REUSE_FROM pch-generator)
+target_include_directories(updated_props PRIVATE ${CMAKE_BINARY_DIR})
+
+set_target_properties(pch-generator
+  PROPERTIES
+    COMPILE_PDB_NAME "custom-post"
+    COMPILE_PDB_NAME_DEBUG "custom-post-debug"
+    COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/custom"
+    COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}/custom-debug")
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseWithoutPch-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/PrecompileHeaders/PchReuseWithoutPch-result.txt
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseWithoutPch-stderr.txt b/Tests/RunCMake/PrecompileHeaders/PchReuseWithoutPch-stderr.txt
new file mode 100644
index 0000000..a2d912b
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseWithoutPch-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error in CMakeLists.txt:
+  Target "pch-generator" for the "reuse_from_nopch" target's
+  "PRECOMPILE_HEADERS_REUSE_FROM" property has set
+  "DISABLE_PRECOMPILE_HEADERS".
diff --git a/Tests/RunCMake/PrecompileHeaders/PchReuseWithoutPch.cmake b/Tests/RunCMake/PrecompileHeaders/PchReuseWithoutPch.cmake
new file mode 100644
index 0000000..316793e
--- /dev/null
+++ b/Tests/RunCMake/PrecompileHeaders/PchReuseWithoutPch.cmake
@@ -0,0 +1,60 @@
+enable_language(CXX)
+
+if(CMAKE_CXX_COMPILE_OPTIONS_USE_PCH)
+  add_definitions(-DHAVE_PCH_SUPPORT)
+endif()
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/pch.cxx [=[
+void nothing()
+{
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/string.hxx [=[
+#include <string.h>
+
+namespace std {
+  struct string
+  {
+    char storage[20];
+
+    string(const char* s) {
+      strcpy(storage, s);
+    }
+
+    const char* c_str() const {
+      return storage;
+    }
+  };
+}
+]=])
+
+add_library(pch-generator ${CMAKE_BINARY_DIR}/pch.cxx)
+target_precompile_headers(pch-generator PRIVATE ${CMAKE_BINARY_DIR}/string.hxx)
+set_property(TARGET pch-generator PROPERTY DISABLE_PRECOMPILE_HEADERS 1)
+
+######################################################################
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.cxx [=[
+#include "message.hxx"
+
+#ifndef HAVE_PCH_SUPPORT
+  #include "string.hxx"
+#endif
+
+const char* message()
+{
+  static std::string greeting("hi there");
+  return greeting.c_str();
+}
+]=])
+
+file(WRITE ${CMAKE_BINARY_DIR}/message.hxx [=[
+const char* message();
+]=])
+
+add_library(reuse_from_nopch ${CMAKE_BINARY_DIR}/message.cxx)
+target_precompile_headers(reuse_from_nopch REUSE_FROM pch-generator)
+target_include_directories(reuse_from_nopch PRIVATE ${CMAKE_BINARY_DIR})
diff --git a/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid.cmake b/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid.cmake
index 4525664..d70d4a4 100644
--- a/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/PchWarnInvalid.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 
 set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
diff --git a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
index 139d586..60e3ad3 100644
--- a/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/RunCMakeTest.cmake
@@ -8,9 +8,22 @@
   run_cmake_command(${name}-test ${CMAKE_CTEST_COMMAND} -C Debug)
 endfunction()
 
+function(run_build_verbose name)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build)
+  run_cmake(${name})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(${name}-build ${CMAKE_COMMAND} --build . --verbose --config Debug)
+endfunction()
+
 run_cmake(DisabledPch)
 run_cmake(PchDebugGenex)
+if (CMAKE_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+  run_cmake(PchDebugGenexShort)
+endif ()
 run_test(PchInterface)
+if (CMAKE_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+  run_test(PchInterfaceShort)
+endif ()
 run_test(PchInterfaceUnity)
 run_cmake(PchPrologueEpilogue)
 run_test(SkipPrecompileHeaders)
@@ -22,7 +35,14 @@
 endif()
 run_test(PchReuseFromPrefixed)
 run_test(PchReuseFromSubdir)
+run_build_verbose(PchReuseFromIgnoreOwnProps)
+run_build_verbose(PchReuseFromUseUpdatedProps)
+run_build_verbose(PchReuseConsistency)
+run_cmake(PchReuseFromCycle)
+run_cmake(PchReuseWithoutPch)
+run_build_verbose(PchReuseAppend)
 run_cmake(PchMultilanguage)
+run_build_verbose(PchReuseDeclarationOrder)
 if(RunCMake_GENERATOR MATCHES "Make|Ninja")
   run_cmake(PchWarnInvalid)
 
diff --git a/Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake b/Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake
index 7405e65..60a93a0 100644
--- a/Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake
+++ b/Tests/RunCMake/PrecompileHeaders/SkipPrecompileHeaders.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_language(CXX)
 
diff --git a/Tests/RunCMake/Swift/C.c b/Tests/RunCMake/Swift/C.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/Swift/C.c
diff --git a/Tests/RunCMake/Swift/MultiLangChain.cmake b/Tests/RunCMake/Swift/MultiLangChain.cmake
new file mode 100644
index 0000000..f8dccc9
--- /dev/null
+++ b/Tests/RunCMake/Swift/MultiLangChain.cmake
@@ -0,0 +1,10 @@
+cmake_policy(SET CMP0157 NEW)
+cmake_policy(SET CMP0195 NEW)
+
+enable_language(Swift C)
+
+add_library(L L.swift)
+add_library(C C.c)
+target_link_libraries(C PRIVATE L)
+add_library(E E.swift)
+target_link_libraries(E PRIVATE C)
diff --git a/Tests/RunCMake/Swift/RunCMakeTest.cmake b/Tests/RunCMake/Swift/RunCMakeTest.cmake
index 63ad232..bab9230 100644
--- a/Tests/RunCMake/Swift/RunCMakeTest.cmake
+++ b/Tests/RunCMake/Swift/RunCMakeTest.cmake
@@ -30,6 +30,17 @@
   endif()
 endblock()
 
+# Older Xcode versions didn't support Swift static libraries.
+if(NOT (RunCMake_GENERATOR STREQUAL "Xcode" AND XCODE_VERSION VERSION_LESS 9.0))
+  block()
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/MultiLangChain-build)
+    run_cmake(MultiLangChain)
+    set(RunCMake_TEST_NO_CLEAN 1)
+    set(RunCMake_TEST_OUTPUT_MERGE 1)
+    run_cmake_command(MultiLangChain-build ${CMAKE_COMMAND} --build .)
+  endblock()
+endif()
+
 if(RunCMake_GENERATOR MATCHES "Ninja.*")
   block()
     set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0195-NEW-build)
diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
index 80f0047..46af243 100644
--- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
+++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
@@ -47,6 +47,7 @@
    \* CMP0181
    \* CMP0182
    \* CMP0195
+   \* CMP0199
 
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake
index 423262b..eab5abf 100644
--- a/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake
+++ b/Tests/RunCMake/UnityBuild/RunCMakeTest.cmake
@@ -71,3 +71,7 @@
 
 run_test(unitybuild_runtest)
 run_test(unitybuild_object_library)
+
+if (CMAKE_GENERATOR MATCHES "(Ninja|Makefiles|Visual Studio)")
+  run_build(unitybuild_cxx_short)
+endif ()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_anon_ns.cmake b/Tests/RunCMake/UnityBuild/unitybuild_anon_ns.cmake
index e05863d..8f406b4 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_anon_ns.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_anon_ns.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_anon_ns CXX)
 
 include(${CMAKE_CURRENT_SOURCE_DIR}/unitybuild_anon_ns_test_files.cmake)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake b/Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake
index 7caf251..43d5e25 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_batchsize.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_batchsize C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c.cmake
index 77a09cb..68d5a7f 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path.cmake
index 0fe6fbf..7d0b7d8 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_absolute_path.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c_absolute_path C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake
index 073aff2..f8e3b1b 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c_and_cxx C CXX)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path.cmake
index 9c6b0e4..172186b 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_absolute_path.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c_and_cxx_absolute_path C CXX)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group.cmake
index 7bf3f4b..145c62b 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_group.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c_and_cxx C CXX)
 
 set(srcs f.c)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path.cmake
index 21257f4..c2dc7fd 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_and_cxx_relocatable_path.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c_and_cxx_relocatable_path C CXX)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_batch.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_batch.cmake
index 33873b6..5169a99 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_batch.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_batch.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_group.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_group.cmake
index 1fa17f3..b0719c6 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_group.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_group.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path.cmake
index e6046e6..8f9d4e1 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_c_relocatable_path.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c_relocatable_path C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake b/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake
index cc9cc28..38e945b 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_code_before_and_after_include.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_code_before_and_after_include C)
 
 set(src "${CMAKE_CURRENT_BINARY_DIR}/s1.c")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake
index be800d7..92ee5a7 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_cxx CXX)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path.cmake
index 07543f4..94af79a 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_absolute_path.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_cxx_absolute_path CXX)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_group.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_group.cmake
index 9804289..726cf76 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_cxx_group.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_group.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_cxx CXX)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path.cmake
index abf672d..20c649d 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_relocatable_path.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_cxx_relocatable_path CXX)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_short-check.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_short-check.cmake
new file mode 100644
index 0000000..3a01280
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_short-check.cmake
@@ -0,0 +1,5 @@
+set(unitybuild_cxx "${RunCMake_TEST_BINARY_DIR}/.o/9bc0d702/Unity/unity_0_cxx.cxx")
+if(NOT EXISTS "${unitybuild_cxx}")
+  set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_cxx} does not exist.")
+  return()
+endif()
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_cxx_short.cmake b/Tests/RunCMake/UnityBuild/unitybuild_cxx_short.cmake
new file mode 100644
index 0000000..07a23b2
--- /dev/null
+++ b/Tests/RunCMake/UnityBuild/unitybuild_cxx_short.cmake
@@ -0,0 +1,14 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+project(unitybuild_cxx_short CXX)
+
+set(srcs "")
+foreach(s RANGE 1 8)
+  set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.cxx")
+  file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
+  list(APPEND srcs "${src}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON)
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake b/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake
index 60b9875..e547571 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_default_batchsize.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_default_batchsize C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_order.cmake b/Tests/RunCMake/UnityBuild/unitybuild_order.cmake
index 819603d..08490cb 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_order.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_order.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_order C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations.cmake b/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations.cmake
index a28d89e..5b267fc 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_relocatable_locations.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_relocatable_locations C)
 
 # Binary path relative source file
diff --git a/Tests/RunCMake/UnityBuild/unitybuild_skip.cmake b/Tests/RunCMake/UnityBuild/unitybuild_skip.cmake
index 94e5aa3..fe1089a 100644
--- a/Tests/RunCMake/UnityBuild/unitybuild_skip.cmake
+++ b/Tests/RunCMake/UnityBuild/unitybuild_skip.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_skip C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/VS10Project/NoImpLib.cmake b/Tests/RunCMake/VS10Project/NoImpLib.cmake
index 2c11eac..b1e5093 100644
--- a/Tests/RunCMake/VS10Project/NoImpLib.cmake
+++ b/Tests/RunCMake/VS10Project/NoImpLib.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 set(CMAKE_IMPORT_LIBRARY_SUFFIX  "")
 add_library(foo SHARED empty.c)
diff --git a/Tests/RunCMake/VS10Project/NoImpLibShort-build-stdout.txt b/Tests/RunCMake/VS10Project/NoImpLibShort-build-stdout.txt
new file mode 100644
index 0000000..c7282bd
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/NoImpLibShort-build-stdout.txt
@@ -0,0 +1 @@
+.*-Fo.o\\75d55f79\\cf59cf.o.*
diff --git a/Tests/RunCMake/VS10Project/NoImpLibShort.cmake b/Tests/RunCMake/VS10Project/NoImpLibShort.cmake
new file mode 100644
index 0000000..98f80de
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/NoImpLibShort.cmake
@@ -0,0 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(C)
+set(CMAKE_IMPORT_LIBRARY_SUFFIX  "")
+add_library(foo SHARED empty.c)
diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
index 72b1c78..df36a7b 100644
--- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake
@@ -43,7 +43,7 @@
 run_cmake(VsDpiAwareBadParam)
 run_cmake(VsForceInclude)
 run_cmake(VsPrecompileHeaders)
-run_cmake(VsPrecompileHeadersReuseFromCompilePDBName)
+run_cmake(VsPrecompileHeadersShort)
 run_cmake(VsDeployEnabled)
 run_cmake(VsSettings)
 run_cmake(VsSourceSettingsTool)
@@ -73,11 +73,13 @@
   run_cmake(UnityBuildPre2017)
 else()
   run_cmake(UnityBuildNative)
+  run_cmake(UnityBuildNativeShort)
   run_cmake(UnityBuildNativeGrouped)
+  run_cmake(UnityBuildNativeGroupedShort)
 
-  function(run_UnityBuildPCH)
-    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/UnityBuildPCH-build)
-    run_cmake(UnityBuildPCH)
+  function(run_UnityBuildPCH suffix)
+    set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/UnityBuildPCH${suffix}-build)
+    run_cmake(UnityBuildPCH${suffix})
     set(RunCMake_TEST_NO_CLEAN 1)
     set(vcxproj "${RunCMake_TEST_BINARY_DIR}/UnityBuildPCH.vcxproj")
     if(EXISTS "${vcxproj}")
@@ -85,10 +87,11 @@
     endif()
     if(vcxproj_strings MATCHES "Include=\"([^\"]+)\"")
       set(src "${CMAKE_MATCH_1}")
-      run_cmake_command(UnityBuildPCH-build ${CMAKE_COMMAND} --build . --config Debug --target UnityBuildPCH -- -t:ClCompile -p:SelectedFiles=${src})
+      run_cmake_command(UnityBuildPCH${suffix}-build ${CMAKE_COMMAND} --build . --config Debug --target UnityBuildPCH -- -t:ClCompile -p:SelectedFiles=${src})
     endif()
   endfunction()
-  run_UnityBuildPCH()
+  run_UnityBuildPCH("")
+  run_UnityBuildPCH(Short)
 endif()
 
 run_cmake(VsDotnetStartupObject)
@@ -104,3 +107,6 @@
 if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.20)
   run_cmake(VsCLRNetcore)
 endif()
+
+run_cmake(NoImpLibShort)
+run_cmake(RuntimeLibraryShort)
diff --git a/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake
index d7787c8..a779bc9 100644
--- a/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake
+++ b/Tests/RunCMake/VS10Project/RuntimeLibrary.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 set(CMAKE_CONFIGURATION_TYPES Debug)
 cmake_policy(SET CMP0091 NEW)
 enable_language(C)
diff --git a/Tests/RunCMake/VS10Project/RuntimeLibraryShort-build-stdout.txt b/Tests/RunCMake/VS10Project/RuntimeLibraryShort-build-stdout.txt
new file mode 100644
index 0000000..c7282bd
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/RuntimeLibraryShort-build-stdout.txt
@@ -0,0 +1 @@
+.*-Fo.o\\75d55f79\\cf59cf.o.*
diff --git a/Tests/RunCMake/VS10Project/RuntimeLibraryShort.cmake b/Tests/RunCMake/VS10Project/RuntimeLibraryShort.cmake
new file mode 100644
index 0000000..2f6797d
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/RuntimeLibraryShort.cmake
@@ -0,0 +1,22 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+set(CMAKE_CONFIGURATION_TYPES Debug)
+cmake_policy(SET CMP0091 NEW)
+enable_language(C)
+enable_language(CXX)
+
+add_library(default-C empty.c)
+add_library(default-CXX empty.cxx)
+
+set(CMAKE_MSVC_RUNTIME_LIBRARY "")
+add_library(empty-C empty.c)
+add_library(empty-CXX empty.cxx)
+
+set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebug")
+add_library(MTd-C empty.c)
+add_library(MTd-CXX empty.cxx)
+
+add_library(MT-C empty.c)
+set_property(TARGET MT-C PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
+add_library(MT-CXX empty.cxx)
+set_property(TARGET MT-CXX PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
diff --git a/Tests/RunCMake/VS10Project/UnityBuildNative.cmake b/Tests/RunCMake/VS10Project/UnityBuildNative.cmake
index 77a09cb..68d5a7f 100644
--- a/Tests/RunCMake/VS10Project/UnityBuildNative.cmake
+++ b/Tests/RunCMake/VS10Project/UnityBuildNative.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped.cmake b/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped.cmake
index b740e3b..5a5ea02 100644
--- a/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped.cmake
+++ b/Tests/RunCMake/VS10Project/UnityBuildNativeGrouped.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(unitybuild_c C)
 
 set(srcs "")
diff --git a/Tests/RunCMake/VS10Project/UnityBuildNativeGroupedShort-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildNativeGroupedShort-check.cmake
new file mode 100644
index 0000000..b56cf3b
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/UnityBuildNativeGroupedShort-check.cmake
@@ -0,0 +1,56 @@
+set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/9bc0d702/Unity/unity_poolA_c.c")
+if(NOT EXISTS "${unitybuild_c0}")
+  set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.")
+  return()
+endif()
+
+set(unitybuild_c1 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/9bc0d702/Unity/unity_poolB_c.c")
+if(NOT EXISTS "${unitybuild_c1}")
+  set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c1} does not exist.")
+  return()
+endif()
+
+set(tgt_project "${RunCMake_TEST_BINARY_DIR}/tgt.vcxproj")
+if (NOT EXISTS "${tgt_project}")
+  set(RunCMake_TEST_FAILED "Generated project file ${tgt_project} doesn't exist.")
+  return()
+endif()
+
+file(STRINGS ${tgt_project} tgt_projects_strings)
+
+foreach(line IN LISTS tgt_projects_strings)
+  if (line MATCHES "<EnableUnitySupport>true</EnableUnitySupport>")
+    set(have_unity_support ON)
+  endif()
+
+  if (line MATCHES "<ClCompile Include=.*IncludeInUnityFile=\"false\" CustomUnityFile=\"true\"")
+    list(APPEND unity_source_lines ${line})
+  endif()
+
+  if (line MATCHES "<ClCompile Include=.*IncludeInUnityFile=\"true\" CustomUnityFile=\"true\"")
+    list(APPEND sources_list ${line})
+  endif()
+endforeach()
+
+if (NOT have_unity_support)
+  set(RunCMake_TEST_FAILED "Generated project should include the <EnableUnitySupport> block.")
+  return()
+endif()
+
+string(REPLACE "\\" "/" unity_source_lines "${unity_source_lines}")
+string(FIND "${unity_source_lines}" "CMakeFiles/9bc0d702/Unity/unity_poolA_c.c" unity_source_file_position)
+if (unity_source_file_position EQUAL "-1")
+  set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file 'poolA'.")
+  return()
+endif()
+string(FIND "${unity_source_lines}" "CMakeFiles/9bc0d702/Unity/unity_poolB_c.c" unity_source_file_position)
+if (unity_source_file_position EQUAL "-1")
+  set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file 'poolB'.")
+  return()
+endif()
+
+list(LENGTH sources_list number_of_sources)
+if(NOT number_of_sources EQUAL 7)
+  set(RunCMake_TEST_FAILED "Generated project doesn't include the expect number of files.")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/UnityBuildNativeGroupedShort.cmake b/Tests/RunCMake/VS10Project/UnityBuildNativeGroupedShort.cmake
new file mode 100644
index 0000000..e347448
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/UnityBuildNativeGroupedShort.cmake
@@ -0,0 +1,22 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+project(unitybuild_c C)
+
+set(srcs "")
+foreach(s RANGE 1 8)
+  set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
+  file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
+  list(APPEND srcs "${src}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON UNITY_BUILD_MODE GROUP)
+
+set_source_files_properties(s1.c s2.c s3.c s4.c
+                            PROPERTIES UNITY_GROUP "poolA"
+                            )
+
+set_source_files_properties(s5.c s6.c s7.c
+                            PROPERTIES UNITY_GROUP "poolB"
+                            )
diff --git a/Tests/RunCMake/VS10Project/UnityBuildNativeShort-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildNativeShort-check.cmake
new file mode 100644
index 0000000..941c60f
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/UnityBuildNativeShort-check.cmake
@@ -0,0 +1,45 @@
+set(unitybuild_c0 "${RunCMake_TEST_BINARY_DIR}/CMakeFiles/9bc0d702/Unity/unity_0_c.c")
+if(NOT EXISTS "${unitybuild_c0}")
+  set(RunCMake_TEST_FAILED "Generated unity source files ${unitybuild_c0} does not exist.")
+  return()
+endif()
+
+set(tgt_project "${RunCMake_TEST_BINARY_DIR}/tgt.vcxproj")
+if (NOT EXISTS "${tgt_project}")
+  set(RunCMake_TEST_FAILED "Generated project file ${tgt_project} doesn't exist.")
+  return()
+endif()
+
+file(STRINGS ${tgt_project} tgt_projects_strings)
+
+foreach(line IN LISTS tgt_projects_strings)
+  if (line MATCHES "<EnableUnitySupport>true</EnableUnitySupport>")
+    set(have_unity_support ON)
+  endif()
+
+  if (line MATCHES "<ClCompile Include=.*IncludeInUnityFile=\"false\" CustomUnityFile=\"true\"")
+    set(unity_source_line ${line})
+  endif()
+
+  if (line MATCHES "<ClCompile Include=.*IncludeInUnityFile=\"true\" CustomUnityFile=\"true\"")
+    list(APPEND sources_list ${line})
+  endif()
+endforeach()
+
+if (NOT have_unity_support)
+  set(RunCMake_TEST_FAILED "Generated project should include the <EnableUnitySupport> block.")
+  return()
+endif()
+
+string(REPLACE "\\" "/" unity_source_line "${unity_source_line}")
+string(FIND "${unity_source_line}" "CMakeFiles/9bc0d702/Unity/unity_0_c.c" unity_source_file_position)
+if (unity_source_file_position EQUAL "-1")
+  set(RunCMake_TEST_FAILED "Generated project should include the generated unity source file.")
+  return()
+endif()
+
+list(LENGTH sources_list number_of_sources)
+if(NOT number_of_sources EQUAL 8)
+  set(RunCMake_TEST_FAILED "Generated project doesn't include the expect number of files.")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/UnityBuildNativeShort.cmake b/Tests/RunCMake/VS10Project/UnityBuildNativeShort.cmake
new file mode 100644
index 0000000..404b445
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/UnityBuildNativeShort.cmake
@@ -0,0 +1,14 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+project(unitybuild_c C)
+
+set(srcs "")
+foreach(s RANGE 1 8)
+  set(src "${CMAKE_CURRENT_BINARY_DIR}/s${s}.c")
+  file(WRITE "${src}" "int s${s}(void) { return 0; }\n")
+  list(APPEND srcs "${src}")
+endforeach()
+
+add_library(tgt SHARED ${srcs})
+
+set_target_properties(tgt PROPERTIES UNITY_BUILD ON)
diff --git a/Tests/RunCMake/VS10Project/UnityBuildPCH.cmake b/Tests/RunCMake/VS10Project/UnityBuildPCH.cmake
index 875ffec..8fcd5da 100644
--- a/Tests/RunCMake/VS10Project/UnityBuildPCH.cmake
+++ b/Tests/RunCMake/VS10Project/UnityBuildPCH.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 add_library(UnityBuildPCH STATIC UnityBuildPCH.c)
 target_precompile_headers(UnityBuildPCH PRIVATE UnityBuildPCH.h)
diff --git a/Tests/RunCMake/VS10Project/UnityBuildPCHShort-build-check.cmake b/Tests/RunCMake/VS10Project/UnityBuildPCHShort-build-check.cmake
new file mode 100644
index 0000000..8399a17
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/UnityBuildPCHShort-build-check.cmake
@@ -0,0 +1,10 @@
+set(obj "${RunCMake_TEST_BINARY_DIR}/.o/30e3d702/Debug/3c809d37.obj")
+if(NOT EXISTS "${obj}")
+  set(RunCMake_TEST_FAILED "Expected object file does not exist:\n  ${obj}")
+  return()
+endif()
+set(lib "${RunCMake_TEST_BINARY_DIR}/Debug/UnityBuildPCH.lib")
+if(EXISTS "${lib}")
+  set(RunCMake_TEST_FAILED "Unexpected library file exists:\n  ${lib}")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/UnityBuildPCHShort.cmake b/Tests/RunCMake/VS10Project/UnityBuildPCHShort.cmake
new file mode 100644
index 0000000..085d3fa
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/UnityBuildPCHShort.cmake
@@ -0,0 +1,6 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+enable_language(C)
+add_library(UnityBuildPCH STATIC UnityBuildPCH.c)
+target_precompile_headers(UnityBuildPCH PRIVATE UnityBuildPCH.h)
+set_property(TARGET UnityBuildPCH PROPERTY UNITY_BUILD ON)
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeaders.cmake b/Tests/RunCMake/VS10Project/VsPrecompileHeaders.cmake
index 6d208c9..5c88c96 100644
--- a/Tests/RunCMake/VS10Project/VsPrecompileHeaders.cmake
+++ b/Tests/RunCMake/VS10Project/VsPrecompileHeaders.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 project(VsPrecompileHeaders CXX)
 
 add_library(tgt SHARED empty.cxx)
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-stderr.txt b/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-stderr.txt
deleted file mode 100644
index 2ff57cd..0000000
--- a/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName-stderr.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-CMake Error at VsPrecompileHeadersReuseFromCompilePDBName.cmake:6 \(add_library\):
-  PRECOMPILE_HEADERS_REUSE_FROM property is set on target \("b"\).  Reusable
-  precompile headers requires the COMPILE_PDB_NAME property to have the value
-  "a"
-
-Call Stack \(most recent call first\):
-  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName.cmake b/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName.cmake
deleted file mode 100644
index ec11008..0000000
--- a/Tests/RunCMake/VS10Project/VsPrecompileHeadersReuseFromCompilePDBName.cmake
+++ /dev/null
@@ -1,9 +0,0 @@
-project(VsPrecompileHeadersReuseFromCompilePDBName CXX)
-
-add_library(a SHARED empty.cxx)
-target_precompile_headers(a PRIVATE <windows.h>)
-
-add_library(b SHARED empty.cxx)
-target_precompile_headers(b REUSE_FROM a)
-
-set_target_properties(b PROPERTIES COMPILE_PDB_NAME b)
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeadersShort-check.cmake b/Tests/RunCMake/VS10Project/VsPrecompileHeadersShort-check.cmake
new file mode 100644
index 0000000..df5c319
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsPrecompileHeadersShort-check.cmake
@@ -0,0 +1,66 @@
+set(pch_header "CMakeFiles/9bc0d702/Debug/cmake_pch.hxx")
+set(pch_source [=[CMakeFiles\\9bc0d702\\cmake_pch.cxx]=])
+
+if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${pch_header}")
+  set(RunCMake_TEST_FAILED "Generated PCH header ${pch_header} does not exist.")
+  return()
+endif()
+if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/${pch_source}")
+  set(RunCMake_TEST_FAILED "Generated PCH header ${pch_source} does not exist.")
+  return()
+endif()
+
+set(tgt_project "${RunCMake_TEST_BINARY_DIR}/tgt.vcxproj")
+if (NOT EXISTS "${tgt_project}")
+  set(RunCMake_TEST_FAILED "Generated project file ${tgt_project} doesn't exist.")
+  return()
+endif()
+
+file(STRINGS ${tgt_project} tgt_projects_strings)
+
+foreach(line IN LISTS tgt_projects_strings)
+  if (line MATCHES "<PrecompiledHeader.*>Use</PrecompiledHeader>")
+    set(have_pch_use ON)
+  endif()
+
+  if (line MATCHES "<PrecompiledHeader.*>Create</PrecompiledHeader>")
+    set(have_pch_create ON)
+  endif()
+
+  if (line MATCHES "<PrecompiledHeaderFile.*>.*${pch_header}</PrecompiledHeaderFile>")
+    set(have_pch_header ON)
+  endif()
+
+  if (line MATCHES "<ForcedIncludeFiles.*>.*${pch_header}.*</ForcedIncludeFiles>")
+    set(have_force_pch_header ON)
+  endif()
+
+  if (line MATCHES "<ClCompile Include=.*${pch_source}\">")
+    set(have_pch_source_compile ON)
+  endif()
+endforeach()
+
+if (NOT have_pch_use)
+  set(RunCMake_TEST_FAILED "Generated project should have the <PrecompiledHeader>Use</PrecompiledHeader> block.")
+  return()
+endif()
+
+if (NOT have_pch_create)
+  set(RunCMake_TEST_FAILED "Generated project should have the <PrecompiledHeader>Create</PrecompiledHeader> block.")
+  return()
+endif()
+
+if (NOT have_pch_header)
+  set(RunCMake_TEST_FAILED "Generated project should have the <PrecompiledHeaderFile>${pch_header}</PrecompiledHeaderFile> block.")
+  return()
+endif()
+
+if (NOT have_force_pch_header)
+  set(RunCMake_TEST_FAILED "Generated project should have the <ForcedIncludeFiles>${pch_header}</ForcedIncludeFiles> block.")
+  return()
+endif()
+
+if (NOT have_pch_source_compile)
+  set(RunCMake_TEST_FAILED "Generated project should have the <ClCompile Include=\"${pch_source}\"> block.")
+  return()
+endif()
diff --git a/Tests/RunCMake/VS10Project/VsPrecompileHeadersShort.cmake b/Tests/RunCMake/VS10Project/VsPrecompileHeadersShort.cmake
new file mode 100644
index 0000000..c7b056c
--- /dev/null
+++ b/Tests/RunCMake/VS10Project/VsPrecompileHeadersShort.cmake
@@ -0,0 +1,6 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY SHORT CACHE STRING "" FORCE)
+
+project(VsPrecompileHeaders CXX)
+
+add_library(tgt SHARED empty.cxx)
+target_precompile_headers(tgt PRIVATE stdafx.h)
diff --git a/Tests/RunCMake/VSSolution/CMP0143-OLD-stderr.txt b/Tests/RunCMake/VSSolution/CMP0143-OLD-stderr.txt
new file mode 100644
index 0000000..ea6ac86
--- /dev/null
+++ b/Tests/RunCMake/VSSolution/CMP0143-OLD-stderr.txt
@@ -0,0 +1,8 @@
+^CMake Deprecation Warning at CMakeLists\.txt:[0-9]+ \(cmake_minimum_required\):
+  The OLD behavior for policy CMP0143 will be removed from a future version
+  of CMake\.
+
+  The cmake-policies\(7\) manual explains that the OLD behaviors of all
+  policies are deprecated and that a policy should be set to OLD only under
+  specific short-term circumstances\.  Projects should be ported to the NEW
+  behavior and not rely on setting a policy to OLD\.$
diff --git a/Tests/RunCMake/add_test/TestLauncher.cmake b/Tests/RunCMake/add_test/TestLauncher.cmake
index bef441d..fb43930 100644
--- a/Tests/RunCMake/add_test/TestLauncher.cmake
+++ b/Tests/RunCMake/add_test/TestLauncher.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 enable_testing()
 
diff --git a/Tests/RunCMake/ctest_instrumentation/CMakeLists.txt.in b/Tests/RunCMake/ctest_instrumentation/CMakeLists.txt.in
index 057f708..976364d 100644
--- a/Tests/RunCMake/ctest_instrumentation/CMakeLists.txt.in
+++ b/Tests/RunCMake/ctest_instrumentation/CMakeLists.txt.in
@@ -2,7 +2,7 @@
 @CASE_CMAKELISTS_PREFIX_CODE@
 project(CTestInstrumentation@CASE_NAME@)
 if(USE_INSTRUMENTATION)
-  set(CMAKE_EXPERIMENTAL_INSTRUMENTATION "a37d1069-1972-4901-b9c9-f194aaf2b6e0")
+  set(CMAKE_EXPERIMENTAL_INSTRUMENTATION "d16a3082-c4e1-489b-b90c-55750a334f27")
 endif()
 include(CTest)
 add_executable(main main.c)
diff --git a/Tests/RunCMake/ctest_instrumentation/InstrumentationInCTestXML-check.cmake b/Tests/RunCMake/ctest_instrumentation/InstrumentationInCTestXML-check.cmake
index 141b467..0f80214 100644
--- a/Tests/RunCMake/ctest_instrumentation/InstrumentationInCTestXML-check.cmake
+++ b/Tests/RunCMake/ctest_instrumentation/InstrumentationInCTestXML-check.cmake
@@ -1,3 +1,12 @@
+set(timingDir "${RunCMake_TEST_BINARY_DIR}/.cmake/instrumentation-d16a3082-c4e1-489b-b90c-55750a334f27/v1")
+file(READ "${timingDir}/query/generated/query-0.json" jsonData)
+string(JSON options GET "${jsonData}" options)
+if (options MATCHES cdashVerbose AND NOT ${RunCMake_USE_VERBOSE_INSTRUMENTATION})
+  set(RunCMake_TEST_FAILED "cdashVerbose option not found in generated query despite environment variable")
+elseif (NOT options MATCHES cdashVerbose AND ${RunCMake_USE_VERBOSE_INSTRUMENTATION})
+  set(RunCMake_TEST_FAILED "cdashVerbose option found in generated query despite environment variable")
+endif()
+
 foreach(xml_type Configure Build Test)
   file(GLOB xml_file "${RunCMake_TEST_BINARY_DIR}/Testing/*/${xml_type}.xml")
   if(xml_file)
@@ -29,6 +38,12 @@
       if(NOT xml_content MATCHES "<CmakeBuild")
         set(RunCMake_TEST_FAILED "<CmakeBuild> element not found in Build.xml")
       endif()
+      if(NOT RunCMake_USE_VERBOSE_INSTRUMENTATION AND NOT xml_content MATCHES "(truncated)")
+        set(RunCMake_TEST_FAILED "Commands not truncated despite cdashVerbose option")
+      endif()
+      if(verbose AND xml_content MATCHES "(truncated)")
+        set(RunCMake_TEST_FAILED "Commands truncated despite cdashVerbose option")
+      endif()
     endif()
   else()
     set(RunCMake_TEST_FAILED "${xml_type}.xml not found")
@@ -37,7 +52,7 @@
 
 foreach(dir_to_check "configure" "test" "build/targets" "build/commands")
   file(GLOB leftover_cdash_snippets
-    "${RunCMake_TEST_BINARY_DIR}/.cmake/instrumentation-a37d1069-1972-4901-b9c9-f194aaf2b6e0/v1/cdash/${dir_to_check}/*")
+    "${timingDir}/cdash/${dir_to_check}/*")
   if(leftover_cdash_snippets)
     set(RunCMake_TEST_FAILED "Leftover snippets found in cdash dir: ${leftover_cdash_snippets}")
   endif()
diff --git a/Tests/RunCMake/ctest_instrumentation/RunCMakeTest.cmake b/Tests/RunCMake/ctest_instrumentation/RunCMakeTest.cmake
index 7424b17..da7c616 100644
--- a/Tests/RunCMake/ctest_instrumentation/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_instrumentation/RunCMakeTest.cmake
@@ -1,9 +1,16 @@
 include(RunCTest)
 
-function(run_InstrumentationInCTestXML USE_INSTRUMENTATION)
+function(run_InstrumentationInCTestXML CASE_NAME USE_INSTRUMENTATION USE_VERBOSE_INSTRUMENTATION)
+  if(USE_VERBOSE_INSTRUMENTATION)
+    set(ENV{CTEST_USE_VERBOSE_INSTRUMENTATION} "1")
+    set(RunCMake_USE_VERBOSE_INSTRUMENTATION TRUE)
+  else()
+    set(ENV{CTEST_USE_VERBOSE_INSTRUMENTATION} "0")
+    set(RunCMake_USE_VERBOSE_INSTRUMENTATION FALSE)
+  endif()
   if(USE_INSTRUMENTATION)
     set(ENV{CTEST_USE_INSTRUMENTATION} "1")
-    set(ENV{CTEST_EXPERIMENTAL_INSTRUMENTATION} "a37d1069-1972-4901-b9c9-f194aaf2b6e0")
+    set(ENV{CTEST_EXPERIMENTAL_INSTRUMENTATION} "d16a3082-c4e1-489b-b90c-55750a334f27")
     set(RunCMake_USE_INSTRUMENTATION TRUE)
     set(CASE_NAME InstrumentationInCTestXML)
   else()
@@ -18,5 +25,6 @@
   unset(RunCMake_USE_LAUNCHERS)
   unset(RunCMake_USE_INSTRUMENTATION)
 endfunction()
-run_InstrumentationInCTestXML(ON)
-run_InstrumentationInCTestXML(OFF)
+run_InstrumentationInCTestXML(InstrumentationInCTestXML ON OFF)
+run_InstrumentationInCTestXML(VerboseInstrumentationInCTestXML ON ON)
+run_InstrumentationInCTestXML(NoInstrumentationInCTestXML OFF OFF)
diff --git a/Tests/RunCMake/ctest_labels_for_subprojects/RunCMakeTest.cmake b/Tests/RunCMake/ctest_labels_for_subprojects/RunCMakeTest.cmake
index 9b3b6f4..4149cdb 100644
--- a/Tests/RunCMake/ctest_labels_for_subprojects/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ctest_labels_for_subprojects/RunCMakeTest.cmake
@@ -38,7 +38,7 @@
   if(USE_INSTRUMENTATION)
     set(CASE_CMAKELISTS_SUFFIX_CODE [[
   add_subdirectory(MyThirdPartyDependency)
-  set(CMAKE_EXPERIMENTAL_INSTRUMENTATION "a37d1069-1972-4901-b9c9-f194aaf2b6e0")
+  set(CMAKE_EXPERIMENTAL_INSTRUMENTATION "d16a3082-c4e1-489b-b90c-55750a334f27")
   cmake_instrumentation(DATA_VERSION 1 API_VERSION 1)
     ]])
     set(RunCMake-check-file CTestScriptVariableCommandLine-check.cmake)
diff --git a/Tests/RunCMake/export/AppendExport-stderr.txt b/Tests/RunCMake/export/AppendExport-stderr.txt
index d12124c..bc168d3 100644
--- a/Tests/RunCMake/export/AppendExport-stderr.txt
+++ b/Tests/RunCMake/export/AppendExport-stderr.txt
@@ -1,4 +1,4 @@
 CMake Error at AppendExport.cmake:[0-9]+ \(export\):
-  export Unknown argument: "APPEND".
+  export EXPORT subcommand given unknown argument: "APPEND".
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/export/FindDependencyExport-check.cmake b/Tests/RunCMake/export/FindDependencyExport-check.cmake
index 6917c26..17662a7 100644
--- a/Tests/RunCMake/export/FindDependencyExport-check.cmake
+++ b/Tests/RunCMake/export/FindDependencyExport-check.cmake
@@ -1,35 +1,35 @@
 file(READ "${RunCMake_TEST_BINARY_DIR}/mytargets.cmake" mytargets)
-if("${mytargets}" MATCHES "find_dependency\\(P1")
+if("${mytargets}" MATCHES "__find_dependency_no_return\\(P1")
   string(APPEND RunCMake_TEST_FAILED "P1 dependency should not be exported but it is\n")
 endif()
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P2 \"VERSION\" \"1\\.0\"\\)")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P2")
   string(APPEND RunCMake_TEST_FAILED "P2 dependency should be exported but it is not\n")
 endif()
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P3\\)")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P3")
   string(APPEND RunCMake_TEST_FAILED "P3 dependency should be exported but it is not\n")
 endif()
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P4\\)")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P4")
   string(APPEND RunCMake_TEST_FAILED "P4 dependency should be exported but it is not\n")
 endif()
-if("${mytargets}" MATCHES "find_dependency\\(P5")
+if("${mytargets}" MATCHES "__find_dependency_no_return\\(P5")
   string(APPEND RunCMake_TEST_FAILED "P5 dependency should not be exported but it is\n")
 endif()
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P6\\)")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P6")
   string(APPEND RunCMake_TEST_FAILED "P6 dependency should be exported but it is not\n")
 endif()
-if("${mytargets}" MATCHES "find_dependency\\(P7")
+if("${mytargets}" MATCHES "__find_dependency_no_return\\(P7")
   string(APPEND RunCMake_TEST_FAILED "P7 dependency should not be exported but it is\n")
 endif()
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P3[^
-]*\\)
-find_dependency\\(P2[^
-]*\\)
-find_dependency\\(P8[^
-]*\\)
-find_dependency\\(P6[^
-]*\\)
-find_dependency\\(P9[^
-]*\\)
-find_dependency\\(P4")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P3[^
+]*\\)(.*)
+__find_dependency_no_return\\(P2[^
+]*\\)(.*)
+__find_dependency_no_return\\(P8[^
+]*\\)(.*)
+__find_dependency_no_return\\(P6[^
+]*\\)(.*)
+__find_dependency_no_return\\(P9[^
+]*\\)(.*)
+__find_dependency_no_return\\(P4")
   string(APPEND RunCMake_TEST_FAILED "Dependencies are not in the correct order\n")
 endif()
diff --git a/Tests/RunCMake/export/FindDependencyExportGate-stderr.txt b/Tests/RunCMake/export/FindDependencyExportGate-stderr.txt
index b24e846..5edd16a 100644
--- a/Tests/RunCMake/export/FindDependencyExportGate-stderr.txt
+++ b/Tests/RunCMake/export/FindDependencyExportGate-stderr.txt
@@ -1,4 +1,5 @@
 ^CMake Error at FindDependencyExportGate\.cmake:[0-9]+ \(export\):
-  export Unknown argument: "EXPORT_PACKAGE_DEPENDENCIES"\.
+  export EXPORT subcommand given unknown argument:
+  "EXPORT_PACKAGE_DEPENDENCIES".
 Call Stack \(most recent call first\):
   CMakeLists\.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/export/FindDependencyExportStatic-check.cmake b/Tests/RunCMake/export/FindDependencyExportStatic-check.cmake
index b78bccb..b09cc1b 100644
--- a/Tests/RunCMake/export/FindDependencyExportStatic-check.cmake
+++ b/Tests/RunCMake/export/FindDependencyExportStatic-check.cmake
@@ -1,13 +1,13 @@
 file(READ "${RunCMake_TEST_BINARY_DIR}/mytargets.cmake" mytargets)
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P1")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P1")
   string(APPEND RunCMake_TEST_FAILED "P1 dependency should be exported but it is not\n")
 endif()
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P2")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P2")
   string(APPEND RunCMake_TEST_FAILED "P2 dependency should be exported but it is not\n")
 endif()
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P3")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P3")
   string(APPEND RunCMake_TEST_FAILED "P3 dependency should be exported but it is not\n")
 endif()
-if(NOT "${mytargets}" MATCHES "find_dependency\\(P4")
+if(NOT "${mytargets}" MATCHES "__find_dependency_no_return\\(P4")
   string(APPEND RunCMake_TEST_FAILED "P4 dependency should be exported but it is not\n")
 endif()
diff --git a/Tests/RunCMake/export/OldIface-stderr.txt b/Tests/RunCMake/export/OldIface-stderr.txt
index 3cc1033..3bddf05 100644
--- a/Tests/RunCMake/export/OldIface-stderr.txt
+++ b/Tests/RunCMake/export/OldIface-stderr.txt
@@ -1,4 +1,5 @@
 CMake Error at OldIface.cmake:[0-9]+ \(export\):
-  export Unknown argument: "EXPORT_LINK_INTERFACE_LIBRARIES".
+  export EXPORT subcommand given unknown argument:
+  "EXPORT_LINK_INTERFACE_LIBRARIES".
 Call Stack \(most recent call first\):
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_dependency/bad-version-exact-stderr.txt b/Tests/RunCMake/find_dependency/bad-version-exact-stderr.txt
index 0929f84..26782e9 100644
--- a/Tests/RunCMake/find_dependency/bad-version-exact-stderr.txt
+++ b/Tests/RunCMake/find_dependency/bad-version-exact-stderr.txt
@@ -7,5 +7,7 @@
     .*/Tests/RunCMake/find_dependency/share/cmake/Pack1/Pack1Config.cmake, version: 1.3
 
 Call Stack \(most recent call first\):
+  [^
+]*/Modules/CMakeFindDependencyMacro.cmake:[0-9]+ \(__find_dependency_common\)
   bad-version-exact.cmake:5 \(find_dependency\)
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_dependency/bad-version-fuzzy-stderr.txt b/Tests/RunCMake/find_dependency/bad-version-fuzzy-stderr.txt
index c63256f..a455a37 100644
--- a/Tests/RunCMake/find_dependency/bad-version-fuzzy-stderr.txt
+++ b/Tests/RunCMake/find_dependency/bad-version-fuzzy-stderr.txt
@@ -7,5 +7,7 @@
     .*/Tests/RunCMake/find_dependency/share/cmake/Pack1/Pack1Config.cmake, version: 1.3
 
 Call Stack \(most recent call first\):
+  [^
+]*/Modules/CMakeFindDependencyMacro.cmake:[0-9]+ \(__find_dependency_common\)
   bad-version-fuzzy.cmake:5 \(find_dependency\)
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_dependency/invalid-arg-stderr.txt b/Tests/RunCMake/find_dependency/invalid-arg-stderr.txt
index 16077b2..20572d9 100644
--- a/Tests/RunCMake/find_dependency/invalid-arg-stderr.txt
+++ b/Tests/RunCMake/find_dependency/invalid-arg-stderr.txt
@@ -1,5 +1,7 @@
 CMake Error at .*Modules/CMakeFindDependencyMacro.cmake:[0-9]+ \(find_package\):
   find_package called with invalid argument "EXACTYPO"
 Call Stack \(most recent call first\):
+  [^
+]*/Modules/CMakeFindDependencyMacro.cmake:[0-9]+ \(__find_dependency_common\)
   invalid-arg.cmake:5 \(find_dependency\)
   CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package-CPS/License.cmake b/Tests/RunCMake/find_package-CPS/License.cmake
new file mode 100644
index 0000000..623dbc7
--- /dev/null
+++ b/Tests/RunCMake/find_package-CPS/License.cmake
@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 4.0)
+
+include(Setup.cmake)
+
+set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
+set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
+
+find_package(LicenseTest REQUIRED)
+
+function(expect_license COMPONENT EXPECTED)
+  set(target LicenseTest::${COMPONENT})
+  if(TARGET ${target})
+    get_target_property(license ${target} "SPDX_LICENSE")
+    if (NOT "${license}" STREQUAL "${EXPECTED}")
+      message(SEND_ERROR
+        "Target ${target} has wrong license '${license}'"
+        " (expected '${EXPECTED}') !")
+    endif()
+  else()
+    message(SEND_ERROR "Expected target ${target} was not found !")
+  endif()
+endfunction()
+
+expect_license(SpecifiedOnTarget "Apache-2.0")
+expect_license(InheritFromRoot "BSD-3-Clause")
+expect_license(InheritFromAppendix "Apache-2.0")
+expect_license(DisableInheritance "license-NOTFOUND")
diff --git a/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake b/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake
index 1bcdc8a..cbc636a 100644
--- a/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_package-CPS/RunCMakeTest.cmake
@@ -18,7 +18,7 @@
 run_cmake(CustomVersion)
 
 # Metadata Tests
-run_cmake(SupplementalAttributes)
+run_cmake(License)
 
 # Version-matching failure tests
 run_cmake(MissingVersion1)
diff --git a/Tests/RunCMake/find_package-CPS/SupplementalAttributes.cmake b/Tests/RunCMake/find_package-CPS/SupplementalAttributes.cmake
deleted file mode 100644
index 3d6d567..0000000
--- a/Tests/RunCMake/find_package-CPS/SupplementalAttributes.cmake
+++ /dev/null
@@ -1,13 +0,0 @@
-cmake_minimum_required(VERSION 4.0)
-
-include(Setup.cmake)
-
-set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
-set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
-
-find_package(SupplementalAttributesTest REQUIRED COMPONENTS Sample)
-
-get_target_property(license SupplementalAttributesTest::Sample "SPDX_LICENSE")
-if (NOT "${license}" STREQUAL "BSD-3-Clause")
-  message(SEND_ERROR "SupplementalAttributesTest wrong license ${license} !")
-endif()
diff --git a/Tests/RunCMake/find_package-CPS/cps/licensetest-notinherited.cps b/Tests/RunCMake/find_package-CPS/cps/licensetest-notinherited.cps
new file mode 100644
index 0000000..0ba7dd1
--- /dev/null
+++ b/Tests/RunCMake/find_package-CPS/cps/licensetest-notinherited.cps
@@ -0,0 +1,11 @@
+{
+  "cps_version": "0.13",
+  "name": "LicenseTest",
+  "default_license": "",
+  "cps_path": "@prefix@/cps",
+  "components": {
+    "DisableInheritance": {
+      "type": "interface"
+    }
+  }
+}
diff --git a/Tests/RunCMake/find_package-CPS/cps/licensetest-override.cps b/Tests/RunCMake/find_package-CPS/cps/licensetest-override.cps
new file mode 100644
index 0000000..01d8900
--- /dev/null
+++ b/Tests/RunCMake/find_package-CPS/cps/licensetest-override.cps
@@ -0,0 +1,11 @@
+{
+  "cps_version": "0.13",
+  "name": "LicenseTest",
+  "default_license": "Apache-2.0",
+  "cps_path": "@prefix@/cps",
+  "components": {
+    "InheritFromAppendix": {
+      "type": "interface"
+    }
+  }
+}
diff --git a/Tests/RunCMake/find_package-CPS/cps/licensetest.cps b/Tests/RunCMake/find_package-CPS/cps/licensetest.cps
new file mode 100644
index 0000000..f376933
--- /dev/null
+++ b/Tests/RunCMake/find_package-CPS/cps/licensetest.cps
@@ -0,0 +1,16 @@
+{
+  "cps_version": "0.13",
+  "name": "LicenseTest",
+  "version": "1.0",
+  "default_license": "BSD-3-Clause",
+  "cps_path": "@prefix@/cps",
+  "components": {
+    "SpecifiedOnTarget": {
+      "type": "interface",
+      "license": "Apache-2.0"
+    },
+    "InheritFromRoot": {
+      "type": "interface"
+    }
+  }
+}
diff --git a/Tests/RunCMake/find_package-CPS/cps/supplementalattributestest.cps b/Tests/RunCMake/find_package-CPS/cps/supplementalattributestest.cps
deleted file mode 100644
index c7f3ce4..0000000
--- a/Tests/RunCMake/find_package-CPS/cps/supplementalattributestest.cps
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "cps_version": "0.13",
-  "name": "SupplementalAttributesTest",
-  "version": "1.0",
-  "cps_path": "@prefix@/cps",
-  "components": {
-    "Sample": {
-      "type": "interface",
-      "license": "BSD-3-Clause"
-    }
-  }
-}
diff --git a/Tests/RunCMake/find_package/ConfigureLog.cmake b/Tests/RunCMake/find_package/ConfigureLog.cmake
index 49e785c..3b304a9 100644
--- a/Tests/RunCMake/find_package/ConfigureLog.cmake
+++ b/Tests/RunCMake/find_package/ConfigureLog.cmake
@@ -6,6 +6,7 @@
 set(CMAKE_FIND_DEBUG_MODE 1)
 # Stable sorting for predictable behaviors.
 set(CMAKE_FIND_PACKAGE_SORT_ORDER NAME)
+set(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASCENDING)
 
 # Unset search variables for more predictable output.
 unset(CMAKE_FRAMEWORK_PATH)
diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake
index 10f3453..2ecebc4 100644
--- a/Tests/RunCMake/find_package/RunCMakeTest.cmake
+++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake
@@ -48,6 +48,14 @@
 run_cmake(RequiredVarNested)
 run_cmake(FindRootPathAndPrefixPathAreEqual)
 run_cmake(SetFoundFALSE)
+run_cmake(UnwindIncludeBlock)
+run_cmake(UnwindIncludeFunction)
+run_cmake(UnwindIncludeInvalidContext)
+run_cmake(UnwindIncludeInvalidFindPackage)
+run_cmake(UnwindIncludeInvalidInclude)
+run_cmake(UnwindIncludeNoUnwind)
+run_cmake(UnwindIncludeOnly)
+run_cmake(UnwindIncludeSecondary)
 run_cmake(WrongVersion)
 run_cmake(WrongVersionConfig)
 run_cmake(CMP0084-OLD)
diff --git a/Tests/RunCMake/find_package/UnwindInclude/NoOp.cmake b/Tests/RunCMake/find_package/UnwindInclude/NoOp.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/NoOp.cmake
diff --git a/Tests/RunCMake/find_package/UnwindInclude/NoUnwind.cmake b/Tests/RunCMake/find_package/UnwindInclude/NoUnwind.cmake
new file mode 100644
index 0000000..5e8c11f
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/NoUnwind.cmake
@@ -0,0 +1,2 @@
+find_package(SecondarySuccessful UNWIND_INCLUDE)
+include(${CMAKE_CURRENT_LIST_DIR}/NoOp.cmake)
diff --git a/Tests/RunCMake/find_package/UnwindInclude/PrimaryUnwindConfig.cmake b/Tests/RunCMake/find_package/UnwindInclude/PrimaryUnwindConfig.cmake
new file mode 100644
index 0000000..59952ad
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/PrimaryUnwindConfig.cmake
@@ -0,0 +1,2 @@
+include(${CMAKE_CURRENT_LIST_DIR}/${UNWIND_TARGET}.cmake)
+set(PrimaryUnwind_FOUND true)
diff --git a/Tests/RunCMake/find_package/UnwindInclude/SecondarySuccessfulConfig.cmake b/Tests/RunCMake/find_package/UnwindInclude/SecondarySuccessfulConfig.cmake
new file mode 100644
index 0000000..33efc40
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/SecondarySuccessfulConfig.cmake
@@ -0,0 +1 @@
+set(SecondarySuccessful_FOUND true)
diff --git a/Tests/RunCMake/find_package/UnwindInclude/SecondaryUnwindConfig.cmake b/Tests/RunCMake/find_package/UnwindInclude/SecondaryUnwindConfig.cmake
new file mode 100644
index 0000000..a172bdd
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/SecondaryUnwindConfig.cmake
@@ -0,0 +1 @@
+set(SecondaryUnwind_FOUND false)
diff --git a/Tests/RunCMake/find_package/UnwindInclude/UnwindBlock.cmake b/Tests/RunCMake/find_package/UnwindInclude/UnwindBlock.cmake
new file mode 100644
index 0000000..927a619
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/UnwindBlock.cmake
@@ -0,0 +1,14 @@
+set(RunCMake_TEST_FAILED "Failed to observe side effects of block() scopes during unwind")
+
+block()
+  find_package(foo UNWIND_INCLUDE)
+endblock()
+
+block(PROPAGATE BLOCK_RUN PrimaryUnwind_FOUND)
+  set(BLOCK_RUN true)
+  set(PrimaryUnwind_FOUND false)
+endblock()
+
+if(BLOCK_RUN)
+  set(RunCMake_TEST_FAILED)
+endif()
diff --git a/Tests/RunCMake/find_package/UnwindInclude/UnwindFunction.cmake b/Tests/RunCMake/find_package/UnwindInclude/UnwindFunction.cmake
new file mode 100644
index 0000000..409a0d6
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/UnwindFunction.cmake
@@ -0,0 +1,20 @@
+cmake_policy(SET CMP0140 NEW)
+
+function(f)
+  find_package(foo UNWIND_INCLUDE)
+endfunction()
+
+function(g)
+  set(FUNC_CALLED true)
+  set(PrimaryUnwind_FOUND false)
+  return(PROPAGATE func_called PrimaryUnwind_FOUND)
+endfunction()
+
+set(RunCMake_TEST_FAILED "Failed to observe side effects of function() calls during unwind")
+
+f()
+g()
+
+if(FUNC_CALLED)
+  set(RunCMake_TEST_FAILED)
+endif()
diff --git a/Tests/RunCMake/find_package/UnwindInclude/UnwindInvalidFindPackage.cmake b/Tests/RunCMake/find_package/UnwindInclude/UnwindInvalidFindPackage.cmake
new file mode 100644
index 0000000..d3b4657
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/UnwindInvalidFindPackage.cmake
@@ -0,0 +1,2 @@
+find_package(foo UNWIND_INCLUDE)
+find_package(bar)
diff --git a/Tests/RunCMake/find_package/UnwindInclude/UnwindInvalidInclude.cmake b/Tests/RunCMake/find_package/UnwindInclude/UnwindInvalidInclude.cmake
new file mode 100644
index 0000000..01bb8fe
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/UnwindInvalidInclude.cmake
@@ -0,0 +1,2 @@
+find_package(foo UNWIND_INCLUDE)
+include(${CMAKE_CURRENT_LIST_DIR}/NoOp.cmake)
diff --git a/Tests/RunCMake/find_package/UnwindInclude/UnwindOnly.cmake b/Tests/RunCMake/find_package/UnwindInclude/UnwindOnly.cmake
new file mode 100644
index 0000000..4eecde2
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/UnwindOnly.cmake
@@ -0,0 +1,2 @@
+find_package(foo UNWIND_INCLUDE)
+set(PrimaryUnwind_FOUND false)
diff --git a/Tests/RunCMake/find_package/UnwindInclude/UnwindSecondary.cmake b/Tests/RunCMake/find_package/UnwindInclude/UnwindSecondary.cmake
new file mode 100644
index 0000000..05c479e
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindInclude/UnwindSecondary.cmake
@@ -0,0 +1,2 @@
+find_package(SecondaryUnwind UNWIND_INCLUDE)
+set(PrimaryUnwind_FOUND false)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeBlock-stderr.txt b/Tests/RunCMake/find_package/UnwindIncludeBlock-stderr.txt
new file mode 100644
index 0000000..22df337
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeBlock-stderr.txt
@@ -0,0 +1,30 @@
+CMake Warning at UnwindInclude/UnwindBlock.cmake:4 \(find_package\):
+  By not providing "Findfoo.cmake" in CMAKE_MODULE_PATH this project has
+  asked CMake to find a package configuration file provided by "foo", but
+  CMake did not find one.
+
+  Could not find a package configuration file provided by "foo" with any of
+  the following names:
+
+    fooConfig.cmake
+    foo-config.cmake
+
+  Add the installation prefix of "foo" to CMAKE_PREFIX_PATH or set "foo_DIR"
+  to a directory containing one of the above files.  If "foo" provides a
+  separate development package or SDK, be sure it has been installed.
+Call Stack \(most recent call first\):
+  UnwindInclude/PrimaryUnwindConfig.cmake:1 \(include\)
+  UnwindIncludeBlock.cmake:5 \(find_package\)
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Warning at UnwindIncludeBlock.cmake:5 \(find_package\):
+  Found package configuration file:
+
+    [^
+]*/Tests/RunCMake/find_package/UnwindInclude/PrimaryUnwindConfig.cmake
+
+  but it set PrimaryUnwind_FOUND to FALSE so package "PrimaryUnwind" is
+  considered to be NOT FOUND.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeBlock.cmake b/Tests/RunCMake/find_package/UnwindIncludeBlock.cmake
new file mode 100644
index 0000000..c93ed05
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeBlock.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0074 NEW)
+set(PrimaryUnwind_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/UnwindInclude)
+
+set(UNWIND_TARGET UnwindBlock)
+find_package(PrimaryUnwind)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeFunction-stderr.txt b/Tests/RunCMake/find_package/UnwindIncludeFunction-stderr.txt
new file mode 100644
index 0000000..bd16779
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeFunction-stderr.txt
@@ -0,0 +1,31 @@
+CMake Warning at UnwindInclude/UnwindFunction.cmake:4 \(find_package\):
+  By not providing "Findfoo.cmake" in CMAKE_MODULE_PATH this project has
+  asked CMake to find a package configuration file provided by "foo", but
+  CMake did not find one.
+
+  Could not find a package configuration file provided by "foo" with any of
+  the following names:
+
+    fooConfig.cmake
+    foo-config.cmake
+
+  Add the installation prefix of "foo" to CMAKE_PREFIX_PATH or set "foo_DIR"
+  to a directory containing one of the above files.  If "foo" provides a
+  separate development package or SDK, be sure it has been installed.
+Call Stack \(most recent call first\):
+  UnwindInclude/UnwindFunction.cmake:15 \(f\)
+  UnwindInclude/PrimaryUnwindConfig.cmake:1 \(include\)
+  UnwindIncludeFunction.cmake:5 \(find_package\)
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Warning at UnwindIncludeFunction.cmake:5 \(find_package\):
+  Found package configuration file:
+
+    [^
+]*/Tests/RunCMake/find_package/UnwindInclude/PrimaryUnwindConfig.cmake
+
+  but it set PrimaryUnwind_FOUND to FALSE so package "PrimaryUnwind" is
+  considered to be NOT FOUND.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeFunction.cmake b/Tests/RunCMake/find_package/UnwindIncludeFunction.cmake
new file mode 100644
index 0000000..41c56b7
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeFunction.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0074 NEW)
+set(PrimaryUnwind_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/UnwindInclude)
+
+set(UNWIND_TARGET UnwindFunction)
+find_package(PrimaryUnwind)
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/find_package/UnwindIncludeInvalidContext-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/find_package/UnwindIncludeInvalidContext-result.txt
diff --git a/Tests/RunCMake/find_package/UnwindIncludeInvalidContext-stderr.txt b/Tests/RunCMake/find_package/UnwindIncludeInvalidContext-stderr.txt
new file mode 100644
index 0000000..e2331d2
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeInvalidContext-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at UnwindIncludeInvalidContext.cmake:5 \(find_package\):
+  find_package called with UNWIND_INCLUDE in an invalid context
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeInvalidContext.cmake b/Tests/RunCMake/find_package/UnwindIncludeInvalidContext.cmake
new file mode 100644
index 0000000..e71e0eb
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeInvalidContext.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0074 NEW)
+set(PrimaryUnwind_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/UnwindInclude)
+
+set(UNWIND_TARGET NoUnwind)
+find_package(PrimaryUnwind UNWIND_INCLUDE)
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/find_package/UnwindIncludeInvalidFindPackage-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/find_package/UnwindIncludeInvalidFindPackage-result.txt
diff --git a/Tests/RunCMake/find_package/UnwindIncludeInvalidFindPackage-stderr.txt b/Tests/RunCMake/find_package/UnwindIncludeInvalidFindPackage-stderr.txt
new file mode 100644
index 0000000..fa4c7a9
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeInvalidFindPackage-stderr.txt
@@ -0,0 +1,26 @@
+CMake Warning at UnwindInclude/UnwindInvalidFindPackage.cmake:1 \(find_package\):
+  By not providing "Findfoo.cmake" in CMAKE_MODULE_PATH this project has
+  asked CMake to find a package configuration file provided by "foo", but
+  CMake did not find one.
+
+  Could not find a package configuration file provided by "foo" with any of
+  the following names:
+
+    fooConfig.cmake
+    foo-config.cmake
+
+  Add the installation prefix of "foo" to CMAKE_PREFIX_PATH or set "foo_DIR"
+  to a directory containing one of the above files.  If "foo" provides a
+  separate development package or SDK, be sure it has been installed.
+Call Stack \(most recent call first\):
+  UnwindInclude/PrimaryUnwindConfig.cmake:1 \(include\)
+  UnwindIncludeInvalidFindPackage.cmake:5 \(find_package\)
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Error at UnwindInclude/UnwindInvalidFindPackage.cmake:2 \(find_package\):
+  find_package called while already in an UNWIND state
+Call Stack \(most recent call first\):
+  UnwindInclude/PrimaryUnwindConfig.cmake:1 \(include\)
+  UnwindIncludeInvalidFindPackage.cmake:5 \(find_package\)
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeInvalidFindPackage.cmake b/Tests/RunCMake/find_package/UnwindIncludeInvalidFindPackage.cmake
new file mode 100644
index 0000000..53feb67
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeInvalidFindPackage.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0074 NEW)
+set(PrimaryUnwind_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/UnwindInclude)
+
+set(UNWIND_TARGET UnwindInvalidFindPackage)
+find_package(PrimaryUnwind)
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/find_package/UnwindIncludeInvalidInclude-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/find_package/UnwindIncludeInvalidInclude-result.txt
diff --git a/Tests/RunCMake/find_package/UnwindIncludeInvalidInclude-stderr.txt b/Tests/RunCMake/find_package/UnwindIncludeInvalidInclude-stderr.txt
new file mode 100644
index 0000000..5414997
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeInvalidInclude-stderr.txt
@@ -0,0 +1,26 @@
+CMake Warning at UnwindInclude/UnwindInvalidInclude.cmake:1 \(find_package\):
+  By not providing "Findfoo.cmake" in CMAKE_MODULE_PATH this project has
+  asked CMake to find a package configuration file provided by "foo", but
+  CMake did not find one.
+
+  Could not find a package configuration file provided by "foo" with any of
+  the following names:
+
+    fooConfig.cmake
+    foo-config.cmake
+
+  Add the installation prefix of "foo" to CMAKE_PREFIX_PATH or set "foo_DIR"
+  to a directory containing one of the above files.  If "foo" provides a
+  separate development package or SDK, be sure it has been installed.
+Call Stack \(most recent call first\):
+  UnwindInclude/PrimaryUnwindConfig.cmake:1 \(include\)
+  UnwindIncludeInvalidInclude.cmake:5 \(find_package\)
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Error at UnwindInclude/UnwindInvalidInclude.cmake:2 \(include\):
+  include called while already in an UNWIND state
+Call Stack \(most recent call first\):
+  UnwindInclude/PrimaryUnwindConfig.cmake:1 \(include\)
+  UnwindIncludeInvalidInclude.cmake:5 \(find_package\)
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeInvalidInclude.cmake b/Tests/RunCMake/find_package/UnwindIncludeInvalidInclude.cmake
new file mode 100644
index 0000000..020dd60
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeInvalidInclude.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0074 NEW)
+set(PrimaryUnwind_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/UnwindInclude)
+
+set(UNWIND_TARGET UnwindInvalidInclude)
+find_package(PrimaryUnwind)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeNoUnwind.cmake b/Tests/RunCMake/find_package/UnwindIncludeNoUnwind.cmake
new file mode 100644
index 0000000..3a3d82d
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeNoUnwind.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0074 NEW)
+set(PrimaryUnwind_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/UnwindInclude)
+
+set(UNWIND_TARGET NoUnwind)
+find_package(PrimaryUnwind)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeOnly-stderr.txt b/Tests/RunCMake/find_package/UnwindIncludeOnly-stderr.txt
new file mode 100644
index 0000000..b5b9853
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeOnly-stderr.txt
@@ -0,0 +1,30 @@
+CMake Warning at UnwindInclude/UnwindOnly.cmake:1 \(find_package\):
+  By not providing "Findfoo.cmake" in CMAKE_MODULE_PATH this project has
+  asked CMake to find a package configuration file provided by "foo", but
+  CMake did not find one.
+
+  Could not find a package configuration file provided by "foo" with any of
+  the following names:
+
+    fooConfig.cmake
+    foo-config.cmake
+
+  Add the installation prefix of "foo" to CMAKE_PREFIX_PATH or set "foo_DIR"
+  to a directory containing one of the above files.  If "foo" provides a
+  separate development package or SDK, be sure it has been installed.
+Call Stack \(most recent call first\):
+  UnwindInclude/PrimaryUnwindConfig.cmake:1 \(include\)
+  UnwindIncludeOnly.cmake:5 \(find_package\)
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Warning at UnwindIncludeOnly.cmake:5 \(find_package\):
+  Found package configuration file:
+
+    [^
+]*/Tests/RunCMake/find_package/UnwindInclude/PrimaryUnwindConfig.cmake
+
+  but it set PrimaryUnwind_FOUND to FALSE so package "PrimaryUnwind" is
+  considered to be NOT FOUND.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeOnly.cmake b/Tests/RunCMake/find_package/UnwindIncludeOnly.cmake
new file mode 100644
index 0000000..4ed69d2
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeOnly.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0074 NEW)
+set(PrimaryUnwind_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/UnwindInclude)
+
+set(UNWIND_TARGET UnwindOnly)
+find_package(PrimaryUnwind)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeSecondary-stderr.txt b/Tests/RunCMake/find_package/UnwindIncludeSecondary-stderr.txt
new file mode 100644
index 0000000..441bda9
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeSecondary-stderr.txt
@@ -0,0 +1,24 @@
+CMake Warning at UnwindInclude/UnwindSecondary.cmake:1 \(find_package\):
+  Found package configuration file:
+
+    [^
+]*/Tests/RunCMake/find_package/UnwindInclude/SecondaryUnwindConfig.cmake
+
+  but it set SecondaryUnwind_FOUND to FALSE so package "SecondaryUnwind" is
+  considered to be NOT FOUND.
+Call Stack \(most recent call first\):
+  UnwindInclude/PrimaryUnwindConfig.cmake:1 \(include\)
+  UnwindIncludeSecondary.cmake:5 \(find_package\)
+  CMakeLists.txt:3 \(include\)
+
+
+CMake Warning at UnwindIncludeSecondary.cmake:5 \(find_package\):
+  Found package configuration file:
+
+    [^
+]*/Tests/RunCMake/find_package/UnwindInclude/PrimaryUnwindConfig.cmake
+
+  but it set PrimaryUnwind_FOUND to FALSE so package "PrimaryUnwind" is
+  considered to be NOT FOUND.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/find_package/UnwindIncludeSecondary.cmake b/Tests/RunCMake/find_package/UnwindIncludeSecondary.cmake
new file mode 100644
index 0000000..18cb0b8
--- /dev/null
+++ b/Tests/RunCMake/find_package/UnwindIncludeSecondary.cmake
@@ -0,0 +1,5 @@
+cmake_policy(SET CMP0074 NEW)
+set(PrimaryUnwind_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/UnwindInclude)
+
+set(UNWIND_TARGET UnwindSecondary)
+find_package(PrimaryUnwind)
diff --git a/Tests/RunCMake/include/CMP0198-NEW-root-stdout.txt b/Tests/RunCMake/include/CMP0198-NEW-root-stdout.txt
new file mode 100644
index 0000000..420a047
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-NEW-root-stdout.txt
@@ -0,0 +1,6 @@
+-- CMakeLists\.txt: ''.*
+-- CMakeLists\.txt: ''
+-- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- ParentVariableRoot/include2\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableRoot/include1\.cmake'
+-- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- CMakeLists\.txt: ''
diff --git a/Tests/RunCMake/include/CMP0198-NEW-subdir-stdout.txt b/Tests/RunCMake/include/CMP0198-NEW-subdir-stdout.txt
new file mode 100644
index 0000000..f8bfb16
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-NEW-subdir-stdout.txt
@@ -0,0 +1,7 @@
+-- ParentVariableSubDir/CMakeLists\.txt: ''
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/Inc/include2.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/include1\.cmake'
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/Inc/CMakeLists\.txt: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/include1\.cmake'
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/CMakeLists\.txt: ''
diff --git a/Tests/RunCMake/include/CMP0198-NEW-subdir.cmake b/Tests/RunCMake/include/CMP0198-NEW-subdir.cmake
new file mode 100644
index 0000000..4c5deff
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-NEW-subdir.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0198 NEW)
+add_subdirectory(ParentVariableSubDir)
diff --git a/Tests/RunCMake/include/CMP0198-OLD-root-stdout.txt b/Tests/RunCMake/include/CMP0198-OLD-root-stdout.txt
new file mode 100644
index 0000000..8f8ba92
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-OLD-root-stdout.txt
@@ -0,0 +1,6 @@
+-- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'.*
+-- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- ParentVariableRoot/include2\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableRoot/include1\.cmake'
+-- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
diff --git a/Tests/RunCMake/include/CMP0198-OLD-subdir-stdout.txt b/Tests/RunCMake/include/CMP0198-OLD-subdir-stdout.txt
new file mode 100644
index 0000000..2f785ee
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-OLD-subdir-stdout.txt
@@ -0,0 +1,7 @@
+-- ParentVariableSubDir/CMakeLists\.txt: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/Inc/include2.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/include1\.cmake'
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/Inc/CMakeLists\.txt: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/include1\.cmake'
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/CMakeLists\.txt: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
diff --git a/Tests/RunCMake/include/CMP0198-OLD-subdir.cmake b/Tests/RunCMake/include/CMP0198-OLD-subdir.cmake
new file mode 100644
index 0000000..52a211e
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-OLD-subdir.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0198 OLD)
+add_subdirectory(ParentVariableSubDir)
diff --git a/Tests/RunCMake/include/CMP0198-WARN-root-stdout.txt b/Tests/RunCMake/include/CMP0198-WARN-root-stdout.txt
new file mode 100644
index 0000000..8f8ba92
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-WARN-root-stdout.txt
@@ -0,0 +1,6 @@
+-- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'.*
+-- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- ParentVariableRoot/include2\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableRoot/include1\.cmake'
+-- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
diff --git a/Tests/RunCMake/include/CMP0198-WARN-subdir-stdout.txt b/Tests/RunCMake/include/CMP0198-WARN-subdir-stdout.txt
new file mode 100644
index 0000000..2f785ee
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-WARN-subdir-stdout.txt
@@ -0,0 +1,7 @@
+-- ParentVariableSubDir/CMakeLists\.txt: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/Inc/include2.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/include1\.cmake'
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/Inc/CMakeLists\.txt: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/include1\.cmake'
+-- ParentVariableSubDir/include1\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
+-- ParentVariableSubDir/CMakeLists\.txt: '[^']*/Tests/RunCMake/include/ParentVariableSubDir/CMakeLists\.txt'
diff --git a/Tests/RunCMake/include/CMP0198-WARN-subdir.cmake b/Tests/RunCMake/include/CMP0198-WARN-subdir.cmake
new file mode 100644
index 0000000..3b8ef0c
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-WARN-subdir.cmake
@@ -0,0 +1,3 @@
+# Test CMP0198 WARN behavior with subdirectory: should behave like OLD (no warning issued)
+# Do not set CMP0198 policy explicitly
+add_subdirectory(ParentVariableSubDir)
diff --git a/Tests/RunCMake/include/CMP0198-implicit-NEW-root-stdout.txt b/Tests/RunCMake/include/CMP0198-implicit-NEW-root-stdout.txt
new file mode 100644
index 0000000..417fb30
--- /dev/null
+++ b/Tests/RunCMake/include/CMP0198-implicit-NEW-root-stdout.txt
@@ -0,0 +1,6 @@
+-- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'.*
+-- CMakeLists\.txt: ''
+-- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- ParentVariableRoot/include2\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableRoot/include1\.cmake'
+-- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
+-- CMakeLists\.txt: ''
diff --git a/Tests/RunCMake/include/CMakeLists.txt b/Tests/RunCMake/include/CMakeLists.txt
index 3dd7323..b03a9d9 100644
--- a/Tests/RunCMake/include/CMakeLists.txt
+++ b/Tests/RunCMake/include/CMakeLists.txt
@@ -1,9 +1,29 @@
-cmake_minimum_required(VERSION 3.10)
+set(root_test OFF)
+if(RunCMake_TEST STREQUAL "ParentVariableRoot" OR
+   RunCMake_TEST STREQUAL "CMP0198-NEW-root" OR
+   RunCMake_TEST STREQUAL "CMP0198-implicit-NEW-root" OR
+   RunCMake_TEST STREQUAL "CMP0198-OLD-root" OR
+   RunCMake_TEST STREQUAL "CMP0198-WARN-root")
+  set(root_test ON)
+endif()
+
+if(root_test)
+  message(STATUS "CMakeLists.txt: '${CMAKE_PARENT_LIST_FILE}'")
+endif()
+
+if(RunCMake_TEST STREQUAL "CMP0198-implicit-NEW-root")
+  cmake_minimum_required(VERSION 4.1...4.2)
+else()
+  cmake_minimum_required(VERSION 3.10)
+endif()
+
 project(${RunCMake_TEST} NONE)
-if(RunCMake_TEST STREQUAL "ParentVariableRoot")
+
+if(root_test)
   message(STATUS "CMakeLists.txt: '${CMAKE_PARENT_LIST_FILE}'")
   include(ParentVariableRoot/include1.cmake)
   message(STATUS "CMakeLists.txt: '${CMAKE_PARENT_LIST_FILE}'")
   return()
 endif()
+
 include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/include/ParentVariableRoot-stdout.txt b/Tests/RunCMake/include/ParentVariableRoot-stdout.txt
index 0460905..8f8ba92 100644
--- a/Tests/RunCMake/include/ParentVariableRoot-stdout.txt
+++ b/Tests/RunCMake/include/ParentVariableRoot-stdout.txt
@@ -1,3 +1,4 @@
+-- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'.*
 -- CMakeLists\.txt: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
 -- ParentVariableRoot/include1\.cmake: '[^']*/Tests/RunCMake/include/CMakeLists\.txt'
 -- ParentVariableRoot/include2\.cmake: '[^']*/Tests/RunCMake/include/ParentVariableRoot/include1\.cmake'
diff --git a/Tests/RunCMake/include/RunCMakeTest.cmake b/Tests/RunCMake/include/RunCMakeTest.cmake
index 1b0c808..cd5eedb 100644
--- a/Tests/RunCMake/include/RunCMakeTest.cmake
+++ b/Tests/RunCMake/include/RunCMakeTest.cmake
@@ -43,3 +43,21 @@
 run_cmake(CMP0196-WARN)
 run_cmake(CMP0196-NEW-name)
 run_cmake(CMP0196-NEW-path)
+
+# Warn should silently behave like OLD
+# Test old with implicit and explicit policy setting
+run_cmake(CMP0198-OLD-root)
+run_cmake(CMP0198-WARN-root)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_POLICY_DEFAULT_CMP0198=OLD")
+run_cmake(CMP0198-OLD-root)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_POLICY_DEFAULT_CMP0198=NEW")
+run_cmake(CMP0198-NEW-root)
+unset(RunCMake_TEST_OPTIONS)
+run_cmake(CMP0198-implicit-NEW-root)
+run_cmake(CMP0198-OLD-subdir)
+run_cmake(CMP0198-WARN-subdir)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_POLICY_DEFAULT_CMP0198=OLD")
+run_cmake(CMP0198-OLD-subdir)
+set(RunCMake_TEST_OPTIONS "-DCMAKE_POLICY_DEFAULT_CMP0198=NEW")
+run_cmake(CMP0198-NEW-subdir)
+unset(RunCMake_TEST_OPTIONS)
diff --git a/Tests/RunCMake/install/EXPORT-FindDependencyExport-all-check.cmake b/Tests/RunCMake/install/EXPORT-FindDependencyExport-all-check.cmake
index 9b41436..de33244 100644
--- a/Tests/RunCMake/install/EXPORT-FindDependencyExport-all-check.cmake
+++ b/Tests/RunCMake/install/EXPORT-FindDependencyExport-all-check.cmake
@@ -1,4 +1,15 @@
 file(READ "${RunCMake_TEST_BINARY_DIR}/root-all/lib/cmake/mylib/mylib-targets.cmake" contents)
-if(NOT contents MATCHES "include\\(CMakeFindDependencyMacro\\)\nfind_dependency\\(P2\\)\nfind_dependency\\(P1\\)\n")
-  set(RunCMake_TEST_FAILED "Dependencies were not properly exported")
+
+if(NOT contents MATCHES "__find_dependency_no_return\\(P2")
+  string(APPEND RunCMake_TEST_FAILED "P2 dependency should be exported but it is not\n")
+endif()
+
+if(NOT contents MATCHES "__find_dependency_no_return\\(P1")
+  string(APPEND RunCMake_TEST_FAILED "P1 dependency should be exported but it is not\n")
+endif()
+
+if(NOT contents MATCHES "__find_dependency_no_return\\(P2[^
+]*\\)(.*)
+__find_dependency_no_return\\(P1")
+  string(APPEND RunCMake_TEST_FAILED "Dependencies are not in the correct order\n")
 endif()
diff --git a/Tests/RunCMake/install/EXPORT-Unwind-all-check.cmake b/Tests/RunCMake/install/EXPORT-Unwind-all-check.cmake
new file mode 100644
index 0000000..d8c8727
--- /dev/null
+++ b/Tests/RunCMake/install/EXPORT-Unwind-all-check.cmake
@@ -0,0 +1,8 @@
+cmake_policy(SET CMP0074 NEW)
+set(Unwind_ROOT "${RunCMake_TEST_BINARY_DIR}/root-all")
+
+find_package(Unwind CONFIG QUIET)
+
+if(Unwind_FOUND)
+  set(RunCMake_TEST_FAILED "Unwinding failed, package was reported as found")
+endif()
diff --git a/Tests/RunCMake/install/EXPORT-Unwind-stderr.txt b/Tests/RunCMake/install/EXPORT-Unwind-stderr.txt
new file mode 100644
index 0000000..30efcec
--- /dev/null
+++ b/Tests/RunCMake/install/EXPORT-Unwind-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Warning \(dev\) at EXPORT-Unwind\.cmake:[0-9]+ \(install\):
+  CMake's EXPORT_PACKAGE_DEPENDENCIES support is experimental\.  It is meant
+  only for experimentation and feedback to CMake developers\.
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
+This warning is for project developers\.  Use -Wno-dev to suppress it\.$
diff --git a/Tests/RunCMake/install/EXPORT-Unwind.cmake b/Tests/RunCMake/install/EXPORT-Unwind.cmake
new file mode 100644
index 0000000..435682f
--- /dev/null
+++ b/Tests/RunCMake/install/EXPORT-Unwind.cmake
@@ -0,0 +1,12 @@
+set(CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES "1942b4fa-b2c5-4546-9385-83f254070067")
+enable_language(C)
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+
+find_package(P1 REQUIRED)
+
+add_library(Unwind INTERFACE)
+target_link_libraries(Unwind INTERFACE lib1)
+install(TARGETS Unwind EXPORT UnwindTargets)
+install(EXPORT UnwindTargets EXPORT_PACKAGE_DEPENDENCIES DESTINATION lib/cmake/Unwind)
+install(FILES cmake/UnwindConfig.cmake DESTINATION lib/cmake/Unwind)
diff --git a/Tests/RunCMake/install/FILES-TARGET_OBJECTS.cmake b/Tests/RunCMake/install/FILES-TARGET_OBJECTS.cmake
index 40c58ad..a462a8b 100644
--- a/Tests/RunCMake/install/FILES-TARGET_OBJECTS.cmake
+++ b/Tests/RunCMake/install/FILES-TARGET_OBJECTS.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 enable_language(C)
 add_library(objs OBJECT obj1.c obj2.c)
 install(FILES $<TARGET_OBJECTS:objs> DESTINATION objs)
diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake
index 3a121c0..66007fa 100644
--- a/Tests/RunCMake/install/RunCMakeTest.cmake
+++ b/Tests/RunCMake/install/RunCMakeTest.cmake
@@ -187,6 +187,7 @@
 run_install_test(TARGETS-RPATH)
 run_install_test(InstallRequiredSystemLibraries)
 run_install_test(EXPORT-FindDependencyExport)
+run_install_test(EXPORT-Unwind)
 
 set(RunCMake_TEST_OPTIONS "-DCMAKE_POLICY_DEFAULT_CMP0087:STRING=NEW")
 run_install_test(SCRIPT)
diff --git a/Tests/RunCMake/install/cmake/UnwindConfig.cmake b/Tests/RunCMake/install/cmake/UnwindConfig.cmake
new file mode 100644
index 0000000..a41457c
--- /dev/null
+++ b/Tests/RunCMake/install/cmake/UnwindConfig.cmake
@@ -0,0 +1,2 @@
+include(${CMAKE_CURRENT_LIST_DIR}/UnwindTargets.cmake)
+set(Unwind_FOUND true)
diff --git a/Tests/RunCMake/project/Omissions.cmake b/Tests/RunCMake/project/Omissions.cmake
index 79f695f..88f8e82 100644
--- a/Tests/RunCMake/project/Omissions.cmake
+++ b/Tests/RunCMake/project/Omissions.cmake
@@ -20,5 +20,6 @@
 expect_empty(VERSION_PATCH)
 expect_empty(VERSION_TWEAK)
 expect_empty(COMPAT_VERSION)
+expect_empty(SPDX_LICENSE)
 expect_empty(DESCRIPTION)
 expect_empty(HOMEPAGE_URL)
diff --git a/Tests/RunCMake/project/ProjectLicense-stdout.txt b/Tests/RunCMake/project/ProjectLicense-stdout.txt
new file mode 100644
index 0000000..ef08658
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense-stdout.txt
@@ -0,0 +1 @@
+PROJECT_SPDX_LICENSE=BSD-3-Clause
diff --git a/Tests/RunCMake/project/ProjectLicense.cmake b/Tests/RunCMake/project/ProjectLicense.cmake
new file mode 100644
index 0000000..847ee64
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense.cmake
@@ -0,0 +1,5 @@
+project(ProjectLicenseTest SPDX_LICENSE "BSD-3-Clause" LANGUAGES)
+if(NOT PROJECT_SPDX_LICENSE)
+  message(FATAL_ERROR "PROJECT_SPDX_LICENSE expected to be set")
+endif()
+message(STATUS "PROJECT_SPDX_LICENSE=${PROJECT_SPDX_LICENSE}")
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/project/ProjectLicense2-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/project/ProjectLicense2-result.txt
diff --git a/Tests/RunCMake/project/ProjectLicense2-stderr.txt b/Tests/RunCMake/project/ProjectLicense2-stderr.txt
new file mode 100644
index 0000000..b3be849
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense2-stderr.txt
@@ -0,0 +1 @@
+  SPDX_LICENSE may be specified at most once.
diff --git a/Tests/RunCMake/project/ProjectLicense2.cmake b/Tests/RunCMake/project/ProjectLicense2.cmake
new file mode 100644
index 0000000..c3ef751
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicense2.cmake
@@ -0,0 +1 @@
+project(ProjectLicenseTest SPDX_LICENSE "BSD-3-Clause" SPDX_LICENSE "Apache-2.0" LANGUAGES)
diff --git a/Tests/RunCMake/project/ProjectLicenseNoArg-stderr.txt b/Tests/RunCMake/project/ProjectLicenseNoArg-stderr.txt
new file mode 100644
index 0000000..5cb13fa
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicenseNoArg-stderr.txt
@@ -0,0 +1,2 @@
+  SPDX_LICENSE keyword not followed by a value or was followed by a value
+  that expanded to nothing.
diff --git a/Tests/RunCMake/project/ProjectLicenseNoArg.cmake b/Tests/RunCMake/project/ProjectLicenseNoArg.cmake
new file mode 100644
index 0000000..7404e4d
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicenseNoArg.cmake
@@ -0,0 +1 @@
+project(ProjectLicenseTest LANGUAGES NONE SPDX_LICENSE)
diff --git a/Tests/RunCMake/project/ProjectLicenseNoArg2-stderr.txt b/Tests/RunCMake/project/ProjectLicenseNoArg2-stderr.txt
new file mode 100644
index 0000000..5cb13fa
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicenseNoArg2-stderr.txt
@@ -0,0 +1,2 @@
+  SPDX_LICENSE keyword not followed by a value or was followed by a value
+  that expanded to nothing.
diff --git a/Tests/RunCMake/project/ProjectLicenseNoArg2.cmake b/Tests/RunCMake/project/ProjectLicenseNoArg2.cmake
new file mode 100644
index 0000000..4370d5b
--- /dev/null
+++ b/Tests/RunCMake/project/ProjectLicenseNoArg2.cmake
@@ -0,0 +1 @@
+project(ProjectLicenseTest SPDX_LICENSE LANGUAGES NONE)
diff --git a/Tests/RunCMake/project/RunCMakeTest.cmake b/Tests/RunCMake/project/RunCMakeTest.cmake
index 92b6de5..86bdfae 100644
--- a/Tests/RunCMake/project/RunCMakeTest.cmake
+++ b/Tests/RunCMake/project/RunCMakeTest.cmake
@@ -68,6 +68,10 @@
 run_cmake_with_options(ProjectCompatVersionMissingVersion ${opts})
 run_cmake_with_options(ProjectCompatVersionNewer ${opts})
 run_cmake_with_options(ProjectCompatVersionNoArg ${opts})
+run_cmake_with_options(ProjectLicense ${opts})
+run_cmake_with_options(ProjectLicense2 ${opts})
+run_cmake_with_options(ProjectLicenseNoArg ${opts})
+run_cmake_with_options(ProjectLicenseNoArg2 ${opts})
 
 run_cmake(CMP0048-NEW)
 
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/set/CacheMissingArguments-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/set/CacheMissingArguments-result.txt
diff --git a/Tests/RunCMake/set/CacheMissingArguments-stderr.txt b/Tests/RunCMake/set/CacheMissingArguments-stderr.txt
new file mode 100644
index 0000000..35f76a3
--- /dev/null
+++ b/Tests/RunCMake/set/CacheMissingArguments-stderr.txt
@@ -0,0 +1,11 @@
+CMake Error at CacheMissingArguments.cmake:[0-9]+ \(set\):
+  Error after keyword "HELP":
+
+    missing required value
+
+  Error after keyword "TYPE":
+
+    missing required value
+
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/set/CacheMissingArguments.cmake b/Tests/RunCMake/set/CacheMissingArguments.cmake
new file mode 100644
index 0000000..7497587
--- /dev/null
+++ b/Tests/RunCMake/set/CacheMissingArguments.cmake
@@ -0,0 +1,2 @@
+
+set(CACHE{VAR} TYPE HELP VALUE)
diff --git a/Tests/RunCMake/set/CacheSetUnset.cmake b/Tests/RunCMake/set/CacheSetUnset.cmake
new file mode 100644
index 0000000..ad37c31
--- /dev/null
+++ b/Tests/RunCMake/set/CacheSetUnset.cmake
@@ -0,0 +1,73 @@
+set(CACHE{VAR1} VALUE v1 v2)
+if(NOT DEFINED CACHE{VAR1})
+  message(SEND_ERROR "CACHE{VAR1} not defined")
+endif()
+get_property(type CACHE VAR1 PROPERTY TYPE)
+if(NOT type STREQUAL "STRING")
+  message(SEND_ERROR "CACHE{VAR1} TYPE should be \"STRING\", not \"${type}\"")
+endif()
+set(CACHE{VAR1} VALUE v3 v4)
+if(NOT "$CACHE{VAR1}" STREQUAL "v1;v2")
+  message(SEND_ERROR "CACHE{VAR1} value should be \"v1;v2\", not \"$CACHE{VAR1}\"")
+endif()
+set(CACHE{VAR1} FORCE VALUE v3 v4)
+if(NOT "$CACHE{VAR1}" STREQUAL "v3;v4")
+  message(SEND_ERROR "CACHE{VAR1} value should be \"v3;v4\", not \"$CACHE{VAR1}\"")
+endif()
+set(CACHE{VAR1} FORCE VALUE)
+if(NOT DEFINED CACHE{VAR1})
+  message(SEND_ERROR "CACHE{VAR1} not defined")
+endif()
+if(NOT "$CACHE{VAR1}" STREQUAL "")
+  message(SEND_ERROR "CACHE{VAR1} value should be \"\", not \"$CACHE{VAR1}\"")
+endif()
+unset(CACHE{VAR1})
+if(DEFINED CACHE{VAR1})
+  message(SEND_ERROR "CACHE{VAR1} defined")
+endif()
+
+set(CACHE{VAR2} TYPE PATH HELP "help1 " "help2" VALUE v1 v2)
+if(NOT DEFINED CACHE{VAR2})
+  message(SEND_ERROR "CACHE{VAR2} not defined")
+endif()
+get_property(type CACHE VAR2 PROPERTY TYPE)
+if(NOT type STREQUAL "PATH")
+  message(SEND_ERROR "CACHE{VAR2} TYPE should be \"PATH\", not \"${type}\"")
+endif()
+get_property(help CACHE VAR2 PROPERTY HELPSTRING)
+if(NOT help STREQUAL "help1 help2")
+  message(SEND_ERROR "CACHE{VAR2} HELP should be \"help1 help2\", not \"${help}\"")
+endif()
+if(NOT "$CACHE{VAR2}" STREQUAL "v1;v2")
+  message(SEND_ERROR "CACHE{VAR2} value should be \"v1;v2\", not \"$CACHE{VAR2}\"")
+endif()
+set(CACHE{VAR2} FORCE VALUE v3 v4)
+if(NOT "$CACHE{VAR2}" STREQUAL "v3;v4")
+  message(SEND_ERROR "CACHE{VAR2} value should be \"v3;v4\", not \"$CACHE{VAR2}\"")
+endif()
+get_property(type CACHE VAR2 PROPERTY TYPE)
+if(NOT type STREQUAL "PATH")
+  message(SEND_ERROR "CACHE{VAR2} TYPE should be \"PATH\", not \"${type}\"")
+endif()
+get_property(help CACHE VAR2 PROPERTY HELPSTRING)
+if(NOT help STREQUAL "help1 help2")
+  message(SEND_ERROR "CACHE{VAR2} HELP should be \"help1 help2\", not \"${help}\"")
+endif()
+unset(CACHE{VAR2})
+if(DEFINED CACHE{VAR2})
+  message(SEND_ERROR "CACHE{VAR2} defined")
+endif()
+
+
+set(CACHE{VAR3} TYPE INTERNAL HELP "help" VALUE v1 v2)
+if(NOT DEFINED CACHE{VAR3})
+  message(SEND_ERROR "CACHE{VAR3} not defined")
+endif()
+set(CACHE{VAR3} VALUE v3 v4)
+if(NOT "$CACHE{VAR3}" STREQUAL "v3;v4")
+  message(SEND_ERROR "CACHE{VAR3} value should be \"v3;v4\", not \"$CACHE{VAR3}\"")
+endif()
+get_property(type CACHE VAR3 PROPERTY TYPE)
+if(NOT type STREQUAL "INTERNAL")
+  message(SEND_ERROR "CACHE{VAR3} TYPE should be \"INTERNAL\", not \"${type}\"")
+endif()
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/set/CacheUnknownArguments-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/set/CacheUnknownArguments-result.txt
diff --git a/Tests/RunCMake/set/CacheUnknownArguments-stderr.txt b/Tests/RunCMake/set/CacheUnknownArguments-stderr.txt
new file mode 100644
index 0000000..1b5d5bc
--- /dev/null
+++ b/Tests/RunCMake/set/CacheUnknownArguments-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error at CacheUnknownArguments.cmake:[0-9]+ \(set\):
+  set Called with unsupported argument\(s\): FOO.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/set/CacheUnknownArguments.cmake b/Tests/RunCMake/set/CacheUnknownArguments.cmake
new file mode 100644
index 0000000..2ce3f33
--- /dev/null
+++ b/Tests/RunCMake/set/CacheUnknownArguments.cmake
@@ -0,0 +1,2 @@
+
+set(CACHE{VAR} TYPE STRING FOO HELP "help" VALUE)
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/set/CacheWrongTYPE-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/set/CacheWrongTYPE-result.txt
diff --git a/Tests/RunCMake/set/CacheWrongTYPE-stderr.txt b/Tests/RunCMake/set/CacheWrongTYPE-stderr.txt
new file mode 100644
index 0000000..00fa0a6
--- /dev/null
+++ b/Tests/RunCMake/set/CacheWrongTYPE-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at CacheWrongTYPE.cmake:[0-9]+ \(set\):
+  Error after keyword "TYPE":
+
+  Invalid value: FOO.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/set/CacheWrongTYPE.cmake b/Tests/RunCMake/set/CacheWrongTYPE.cmake
new file mode 100644
index 0000000..909d0e5
--- /dev/null
+++ b/Tests/RunCMake/set/CacheWrongTYPE.cmake
@@ -0,0 +1,2 @@
+
+set(CACHE{VAR} TYPE FOO VALUE)
diff --git a/Tests/RunCMake/set/RunCMakeTest.cmake b/Tests/RunCMake/set/RunCMakeTest.cmake
index c785450..2ed4557 100644
--- a/Tests/RunCMake/set/RunCMakeTest.cmake
+++ b/Tests/RunCMake/set/RunCMakeTest.cmake
@@ -6,3 +6,9 @@
 run_cmake(ParentPullingRecursive)
 run_cmake(UnknownCacheType)
 run_cmake(ExtraEnvValue)
+
+# set(CACHE{}) syntax
+run_cmake(CacheUnknownArguments)
+run_cmake(CacheMissingArguments)
+run_cmake(CacheWrongTYPE)
+run_cmake(CacheSetUnset)
diff --git a/Tests/RunCMake/Instrumentation/bad-query-result.txt b/Tests/RunCMake/string/JSONBadJson-result.txt
similarity index 100%
copy from Tests/RunCMake/Instrumentation/bad-query-result.txt
copy to Tests/RunCMake/string/JSONBadJson-result.txt
diff --git a/Tests/RunCMake/string/JSONBadJson-stderr.txt b/Tests/RunCMake/string/JSONBadJson-stderr.txt
new file mode 100644
index 0000000..ba05549
--- /dev/null
+++ b/Tests/RunCMake/string/JSONBadJson-stderr.txt
@@ -0,0 +1,26 @@
+CMake Error at JSONBadJson.cmake:1 \(string\):
+  string sub-command JSON failed parsing json string:
+
+  invalid
+
+  \* Line 1, Column 1
+
+    Syntax error: value, object or array expected.
+
+  .
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
+
+
+CMake Error at JSONBadJson.cmake:2 \(string\):
+  string sub-command JSON failed parsing json string:
+
+  value
+
+  \* Line 1, Column 1
+
+    Syntax error: value, object or array expected.
+
+  .
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:[0-9]+ \(include\)
diff --git a/Tests/RunCMake/string/JSONBadJson.cmake b/Tests/RunCMake/string/JSONBadJson.cmake
new file mode 100644
index 0000000..8daa9f4
--- /dev/null
+++ b/Tests/RunCMake/string/JSONBadJson.cmake
@@ -0,0 +1,3 @@
+string(JSON badInput SET invalid key \"value\")
+string(JSON badValue SET {} key value)
+string(JSON good SET {} key \"value\")
diff --git a/Tests/RunCMake/string/RunCMakeTest.cmake b/Tests/RunCMake/string/RunCMakeTest.cmake
index 7279407..f4a6ff8 100644
--- a/Tests/RunCMake/string/RunCMakeTest.cmake
+++ b/Tests/RunCMake/string/RunCMakeTest.cmake
@@ -6,6 +6,7 @@
 run_cmake(JSONWrongMode)
 run_cmake(JSONOneArg)
 run_cmake(JSONNoArgs)
+run_cmake(JSONBadJson)
 
 run_cmake(Append)
 run_cmake(AppendNoArgs)
diff --git a/Tests/RunCMake/target_compile_options/Order.cmake b/Tests/RunCMake/target_compile_options/Order.cmake
index 3d59b16..f6168fb 100644
--- a/Tests/RunCMake/target_compile_options/Order.cmake
+++ b/Tests/RunCMake/target_compile_options/Order.cmake
@@ -1,3 +1,5 @@
+set(CMAKE_INTERMEDIATE_DIR_STRATEGY FULL CACHE STRING "" FORCE)
+
 get_property (isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
 if(isMultiConfig)
   set(CMAKE_CONFIGURATION_TYPES "Custom" CACHE STRING "" FORCE)
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index 68918f1..22712b7 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeDeveloperReference_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.13...3.31 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.13...4.0 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index 6056030..51ec37a 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -92,8 +92,12 @@
   { include: [ "\"form.h\"", private, "\"cmCursesStandardIncludes.h\"", public ] },
   { include: [ "<form.h>", private, "\"cmCursesStandardIncludes.h\"", public ] },
 
-  # Help IWYU understand our explicit instantiation for cmConstStack.
-  { symbol: [ "cmConstStack::cmConstStack<T, Stack>", private, "\"cmConstStack.h\"", public ] },
+  # Help IWYU understand our explicit instantiation for cmStack.
+  { symbol: [ "cmStack::cmStack<T, Stack, Mutable>", private, "\"cmStack.h\"", public ] },
+  { symbol: [ "cmStack<cmFindPackageCall, cmFindPackageStack, cmStackType::Mutable>::Empty", private, "\"cmStack.h\"", public ] },
+  { symbol: [ "cmStack<cmFindPackageCall, cmFindPackageStack, cmStackType::Mutable>::Top", private, "\"cmStack.h\"", public ] },
+  { symbol: [ "cmStack<cmFindPackageCall, cmFindPackageStack, cmStackType::Mutable>::Pop", private, "\"cmStack.h\"", public ] },
+  { symbol: [ "cmStack<cmFindPackageCall, cmFindPackageStack, cmStackType::Mutable>::Push", private, "\"cmStack.h\"", public ] },
 ]
 
 # vim: set ft=toml:
diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash
index e6b9a9b..bfab6db 100755
--- a/Utilities/Scripts/update-curl.bash
+++ b/Utilities/Scripts/update-curl.bash
@@ -8,7 +8,7 @@
 readonly ownership="Curl Upstream <curl-library@lists.haxx.se>"
 readonly subtree="Utilities/cmcurl"
 readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-8_14_1"
+readonly tag="curl-8_15_0"
 readonly shortlog=false
 readonly paths="
   CMake/*
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
index c89d412..ba19f80 100644
--- a/Utilities/Sphinx/CMakeLists.txt
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -3,7 +3,7 @@
 
 if(NOT CMake_SOURCE_DIR)
   set(CMakeHelp_STANDALONE 1)
-  cmake_minimum_required(VERSION 3.13...3.31 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.13...4.0 FATAL_ERROR)
   get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
   get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
   include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
@@ -27,6 +27,7 @@
 option(SPHINX_QTHELP "Build Qt help with Sphinx" OFF)
 option(SPHINX_LATEXPDF "Build PDF help with Sphinx using LaTeX" OFF)
 option(SPHINX_TEXT "Build text help with Sphinx (not installed)" OFF)
+option(SPHINX_INCLUDE_IN_ALL "Build Sphinx documentation by default" ON)
 find_program(SPHINX_EXECUTABLE
   NAMES sphinx-build
   DOC "Sphinx Documentation Builder (sphinx-doc.org)"
@@ -254,7 +255,11 @@
   endif()
 endforeach()
 
-add_custom_target(documentation ALL DEPENDS ${doc_format_outputs})
+if (SPHINX_INCLUDE_IN_ALL)
+  set(add_documentation_to_all ALL)
+endif()
+
+add_custom_target(documentation ${add_documentation_to_all} DEPENDS ${doc_format_outputs})
 
 if(CMake_SPHINX_DEPEND_ON_EXECUTABLES)
   foreach(t IN ITEMS cmake ccmake cmake-gui cpack ctest)
diff --git a/Utilities/Sphinx/conf.py.in b/Utilities/Sphinx/conf.py.in
index c823587..7df0d4d 100644
--- a/Utilities/Sphinx/conf.py.in
+++ b/Utilities/Sphinx/conf.py.in
@@ -98,6 +98,7 @@
     r'https://web\.archive\.org/',
     r'https://www\.gnu\.org/',
     r'https://www\.intel\.com/',
+    r'https://[a-z0-9]+\.sourceforge\.net/?$',
     r'https://www\.tasking\.com($|/)',
 ]
 
diff --git a/Utilities/cmcurl/CMake/CurlTests.c b/Utilities/cmcurl/CMake/CurlTests.c
index de23130..410a0f7 100644
--- a/Utilities/cmcurl/CMake/CurlTests.c
+++ b/Utilities/cmcurl/CMake/CurlTests.c
@@ -203,7 +203,7 @@
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
-#ifdef HAVE_SYS_SOCKET_H
+#ifndef _WIN32
 #  include <sys/socket.h>
 #endif
 #ifdef HAVE_SYS_IOCTL_H
@@ -230,7 +230,7 @@
 #ifdef HAVE_UNISTD_H
 #  include <unistd.h>
 #endif
-#ifdef HAVE_SYS_SOCKET_H
+#ifndef _WIN32
 #  include <sys/socket.h>
 #endif
 #ifdef HAVE_SYS_IOCTL_H
@@ -257,7 +257,7 @@
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
-#ifdef HAVE_SYS_SOCKET_H
+#ifndef _WIN32
 #  include <sys/socket.h>
 #endif
 int main(void)
diff --git a/Utilities/cmcurl/CMake/FindBearSSL.cmake b/Utilities/cmcurl/CMake/FindBearSSL.cmake
deleted file mode 100644
index ff55be0..0000000
--- a/Utilities/cmcurl/CMake/FindBearSSL.cmake
+++ /dev/null
@@ -1,58 +0,0 @@
-#***************************************************************************
-#                                  _   _ ____  _
-#  Project                     ___| | | |  _ \| |
-#                             / __| | | | |_) | |
-#                            | (__| |_| |  _ <| |___
-#                             \___|\___/|_| \_\_____|
-#
-# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at https://curl.se/docs/copyright.html.
-#
-# You may opt to use, copy, modify, merge, publish, distribute and/or sell
-# copies of the Software, and permit persons to whom the Software is
-# furnished to do so, under the terms of the COPYING file.
-#
-# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
-# KIND, either express or implied.
-#
-# SPDX-License-Identifier: curl
-#
-###########################################################################
-# Find the BearSSL library
-#
-# Input variables:
-#
-# - `BEARSSL_INCLUDE_DIR`:   The BearSSL include directory.
-# - `BEARSSL_LIBRARY`:       Path to `bearssl` library.
-#
-# Result variables:
-#
-# - `BEARSSL_FOUND`:         System has BearSSL.
-# - `BEARSSL_INCLUDE_DIRS`:  The BearSSL include directories.
-# - `BEARSSL_LIBRARIES`:     The BearSSL library names.
-
-if(DEFINED BEARSSL_INCLUDE_DIRS AND NOT DEFINED BEARSSL_INCLUDE_DIR)
-  message(WARNING "BEARSSL_INCLUDE_DIRS is deprecated, use BEARSSL_INCLUDE_DIR instead.")
-  set(BEARSSL_INCLUDE_DIR "${BEARSSL_INCLUDE_DIRS}")
-  unset(BEARSSL_INCLUDE_DIRS)
-endif()
-
-find_path(BEARSSL_INCLUDE_DIR NAMES "bearssl.h")
-find_library(BEARSSL_LIBRARY NAMES "bearssl")
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(BearSSL
-  REQUIRED_VARS
-    BEARSSL_INCLUDE_DIR
-    BEARSSL_LIBRARY
-)
-
-if(BEARSSL_FOUND)
-  set(BEARSSL_INCLUDE_DIRS ${BEARSSL_INCLUDE_DIR})
-  set(BEARSSL_LIBRARIES    ${BEARSSL_LIBRARY})
-endif()
-
-mark_as_advanced(BEARSSL_INCLUDE_DIR BEARSSL_LIBRARY)
diff --git a/Utilities/cmcurl/CMake/FindGSS.cmake b/Utilities/cmcurl/CMake/FindGSS.cmake
index c1802ee..9000445 100644
--- a/Utilities/cmcurl/CMake/FindGSS.cmake
+++ b/Utilities/cmcurl/CMake/FindGSS.cmake
@@ -52,19 +52,23 @@
   "$ENV{GSS_ROOT_DIR}"
 )
 
+set(_gss_CFLAGS "")
+set(_gss_LIBRARY_DIRS "")
+
 # Try to find library using system pkg-config if user did not specify root dir
 if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
   if(CURL_USE_PKGCONFIG)
     find_package(PkgConfig QUIET)
-    pkg_search_module(_GSS ${_gnu_modname} ${_mit_modname} ${_heimdal_modname})
-    list(APPEND _gss_root_hints "${_GSS_PREFIX}")
+    pkg_search_module(_gss ${_gnu_modname} ${_mit_modname} ${_heimdal_modname})
+    list(APPEND _gss_root_hints "${_gss_PREFIX}")
+    set(_gss_version "${_gss_VERSION}")
   endif()
   if(WIN32)
     list(APPEND _gss_root_hints "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
   endif()
 endif()
 
-if(NOT _GSS_FOUND)  # Not found by pkg-config. Let us take more traditional approach.
+if(NOT _gss_FOUND)  # Not found by pkg-config. Let us take more traditional approach.
   find_file(_gss_configure_script
     NAMES
       "krb5-config"
@@ -85,25 +89,29 @@
   )
 
   if(_gss_configure_script)
+
+    set(_gss_INCLUDE_DIRS "")
+    set(_gss_LIBRARIES "")
+
     execute_process(
       COMMAND ${_gss_configure_script} "--cflags" "gssapi"
-      OUTPUT_VARIABLE _GSS_CFLAGS
+      OUTPUT_VARIABLE _gss_cflags_raw
       RESULT_VARIABLE _gss_configure_failed
       OUTPUT_STRIP_TRAILING_WHITESPACE
     )
-    message(STATUS "FindGSS krb5-config --cflags: ${_GSS_CFLAGS}")
+    message(STATUS "FindGSS krb5-config --cflags: ${_gss_cflags_raw}")
     if(NOT _gss_configure_failed)  # 0 means success
-      # Should also work in an odd case when multiple directories are given
-      string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
-      string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
-      string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")
+      # Should also work in an odd case when multiple directories are given.
+      string(STRIP "${_gss_cflags_raw}" _gss_cflags_raw)
+      string(REGEX REPLACE " +-(I)" ";-\\1" _gss_cflags_raw "${_gss_cflags_raw}")
+      string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _gss_cflags_raw "${_gss_cflags_raw}")
 
-      foreach(_flag IN LISTS _GSS_CFLAGS)
+      foreach(_flag IN LISTS _gss_cflags_raw)
         if(_flag MATCHES "^-I")
-          string(REGEX REPLACE "^-I" "" _val "${_flag}")
-          list(APPEND _GSS_INCLUDE_DIRS "${_val}")
+          string(REGEX REPLACE "^-I" "" _flag "${_flag}")
+          list(APPEND _gss_INCLUDE_DIRS "${_flag}")
         else()
-          list(APPEND _GSS_CFLAGS "${_flag}")
+          list(APPEND _gss_CFLAGS "${_flag}")
         endif()
       endforeach()
     endif()
@@ -117,32 +125,32 @@
     message(STATUS "FindGSS krb5-config --libs: ${_gss_lib_flags}")
 
     if(NOT _gss_configure_failed)  # 0 means success
-      # This script gives us libraries and link directories. Blah. We have to deal with it.
+      # This script gives us libraries and link directories.
       string(STRIP "${_gss_lib_flags}" _gss_lib_flags)
       string(REGEX REPLACE " +-(L|l)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
       string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
 
       foreach(_flag IN LISTS _gss_lib_flags)
         if(_flag MATCHES "^-l")
-          string(REGEX REPLACE "^-l" "" _val "${_flag}")
-          list(APPEND _GSS_LIBRARIES "${_val}")
+          string(REGEX REPLACE "^-l" "" _flag "${_flag}")
+          list(APPEND _gss_LIBRARIES "${_flag}")
         elseif(_flag MATCHES "^-L")
-          string(REGEX REPLACE "^-L" "" _val "${_flag}")
-          list(APPEND _GSS_LIBRARY_DIRS "${_val}")
+          string(REGEX REPLACE "^-L" "" _flag "${_flag}")
+          list(APPEND _gss_LIBRARY_DIRS "${_flag}")
         endif()
       endforeach()
     endif()
 
     execute_process(
       COMMAND ${_gss_configure_script} "--version"
-      OUTPUT_VARIABLE _GSS_VERSION
+      OUTPUT_VARIABLE _gss_version
       RESULT_VARIABLE _gss_configure_failed
       OUTPUT_STRIP_TRAILING_WHITESPACE
     )
 
     # Older versions may not have the "--version" parameter. In this case we just do not care.
     if(_gss_configure_failed)
-      set(_GSS_VERSION 0)
+      set(_gss_version 0)
     endif()
 
     execute_process(
@@ -165,7 +173,7 @@
 
   else()  # Either there is no config script or we are on a platform that does not provide one (Windows?)
 
-    find_path(_GSS_INCLUDE_DIRS NAMES "gssapi/gssapi.h"
+    find_path(_gss_INCLUDE_DIRS NAMES "gssapi/gssapi.h"
       HINTS
         ${_gss_root_hints}
       PATH_SUFFIXES
@@ -173,9 +181,9 @@
         "inc"
     )
 
-    if(_GSS_INCLUDE_DIRS)  # jay, we have found something
+    if(_gss_INCLUDE_DIRS)  # jay, we have found something
       cmake_push_check_state()
-      list(APPEND CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIRS}")
+      list(APPEND CMAKE_REQUIRED_INCLUDES "${_gss_INCLUDE_DIRS}")
       check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
 
       if(_gss_have_mit_headers)
@@ -193,7 +201,7 @@
       cmake_pop_check_state()
     else()
       # I am not convinced if this is the right way but this is what autotools do at the moment
-      find_path(_GSS_INCLUDE_DIRS NAMES "gssapi.h"
+      find_path(_gss_INCLUDE_DIRS NAMES "gssapi.h"
         HINTS
           ${_gss_root_hints}
         PATH_SUFFIXES
@@ -201,17 +209,17 @@
           "inc"
       )
 
-      if(_GSS_INCLUDE_DIRS)
+      if(_gss_INCLUDE_DIRS)
         set(GSS_FLAVOUR "Heimdal")
       else()
-        find_path(_GSS_INCLUDE_DIRS NAMES "gss.h"
+        find_path(_gss_INCLUDE_DIRS NAMES "gss.h"
           HINTS
             ${_gss_root_hints}
           PATH_SUFFIXES
             "include"
         )
 
-        if(_GSS_INCLUDE_DIRS)
+        if(_gss_INCLUDE_DIRS)
           set(GSS_FLAVOUR "GNU")
           set(GSS_PC_REQUIRES "gss")
         endif()
@@ -222,7 +230,7 @@
     if(GSS_FLAVOUR)
       set(_gss_libdir_suffixes "")
       set(_gss_libdir_hints ${_gss_root_hints})
-      get_filename_component(_gss_calculated_potential_root "${_GSS_INCLUDE_DIRS}" DIRECTORY)
+      get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY)
       list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root})
 
       if(WIN32)
@@ -256,7 +264,7 @@
         endif()
       endif()
 
-      find_library(_GSS_LIBRARIES NAMES ${_gss_libname}
+      find_library(_gss_LIBRARIES NAMES ${_gss_libname}
         HINTS
           ${_gss_libdir_hints}
         PATH_SUFFIXES
@@ -265,36 +273,36 @@
     endif()
   endif()
 else()
-  # _GSS_MODULE_NAME set since CMake 3.16
-  if(_GSS_MODULE_NAME STREQUAL _gnu_modname OR _GSS_${_gnu_modname}_VERSION)
+  # _gss_MODULE_NAME set since CMake 3.16
+  if(_gss_MODULE_NAME STREQUAL _gnu_modname OR _gss_${_gnu_modname}_VERSION)
     set(GSS_FLAVOUR "GNU")
     set(GSS_PC_REQUIRES "gss")
-    if(NOT _GSS_VERSION)  # for old CMake versions?
-      set(_GSS_VERSION ${_GSS_${_gnu_modname}_VERSION})
+    if(NOT _gss_version)  # for old CMake versions?
+      set(_gss_version ${_gss_${_gnu_modname}_VERSION})
     endif()
-  elseif(_GSS_MODULE_NAME STREQUAL _mit_modname OR _GSS_${_mit_modname}_VERSION)
+  elseif(_gss_MODULE_NAME STREQUAL _mit_modname OR _gss_${_mit_modname}_VERSION)
     set(GSS_FLAVOUR "MIT")
     set(GSS_PC_REQUIRES "mit-krb5-gssapi")
-    if(NOT _GSS_VERSION)  # for old CMake versions?
-      set(_GSS_VERSION ${_GSS_${_mit_modname}_VERSION})
+    if(NOT _gss_version)  # for old CMake versions?
+      set(_gss_version ${_gss_${_mit_modname}_VERSION})
     endif()
   else()
     set(GSS_FLAVOUR "Heimdal")
     set(GSS_PC_REQUIRES "heimdal-gssapi")
-    if(NOT _GSS_VERSION)  # for old CMake versions?
-      set(_GSS_VERSION ${_GSS_${_heimdal_modname}_VERSION})
+    if(NOT _gss_version)  # for old CMake versions?
+      set(_gss_version ${_gss_${_heimdal_modname}_VERSION})
     endif()
   endif()
-  message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_GSS_INCLUDE_DIRS} (found version \"${_GSS_VERSION}\")")
+  message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_gss_INCLUDE_DIRS} (found version \"${_gss_version}\")")
 endif()
 
-string(REPLACE ";" " " _GSS_CFLAGS "${_GSS_CFLAGS}")
+string(REPLACE ";" " " _gss_CFLAGS "${_gss_CFLAGS}")
 
-set(GSS_INCLUDE_DIRS ${_GSS_INCLUDE_DIRS})
-set(GSS_LIBRARIES ${_GSS_LIBRARIES})
-set(GSS_LIBRARY_DIRS ${_GSS_LIBRARY_DIRS})
-set(GSS_CFLAGS ${_GSS_CFLAGS})
-set(GSS_VERSION ${_GSS_VERSION})
+set(GSS_INCLUDE_DIRS ${_gss_INCLUDE_DIRS})
+set(GSS_LIBRARIES ${_gss_LIBRARIES})
+set(GSS_LIBRARY_DIRS ${_gss_LIBRARY_DIRS})
+set(GSS_CFLAGS ${_gss_CFLAGS})
+set(GSS_VERSION ${_gss_version})
 
 if(GSS_FLAVOUR)
   if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal")
@@ -346,12 +354,12 @@
 )
 
 mark_as_advanced(
-  _GSS_CFLAGS
-  _GSS_FOUND
-  _GSS_INCLUDE_DIRS
-  _GSS_LIBRARIES
-  _GSS_LIBRARY_DIRS
-  _GSS_MODULE_NAME
-  _GSS_PREFIX
-  _GSS_VERSION
+  _gss_CFLAGS
+  _gss_FOUND
+  _gss_INCLUDE_DIRS
+  _gss_LIBRARIES
+  _gss_LIBRARY_DIRS
+  _gss_MODULE_NAME
+  _gss_PREFIX
+  _gss_version
 )
diff --git a/Utilities/cmcurl/CMake/FindLibgsasl.cmake b/Utilities/cmcurl/CMake/FindLibgsasl.cmake
index c726ce1..878d651 100644
--- a/Utilities/cmcurl/CMake/FindLibgsasl.cmake
+++ b/Utilities/cmcurl/CMake/FindLibgsasl.cmake
@@ -66,12 +66,12 @@
   endif()
 
   include(FindPackageHandleStandardArgs)
-    find_package_handle_standard_args(Libgsasl
-    REQUIRED_VARS
-      LIBGSASL_INCLUDE_DIR
-      LIBGSASL_LIBRARY
-    VERSION_VAR
-      LIBGSASL_VERSION
+  find_package_handle_standard_args(Libgsasl
+  REQUIRED_VARS
+    LIBGSASL_INCLUDE_DIR
+    LIBGSASL_LIBRARY
+  VERSION_VAR
+    LIBGSASL_VERSION
   )
 
   if(LIBGSASL_FOUND)
diff --git a/Utilities/cmcurl/CMake/FindNGTCP2.cmake b/Utilities/cmcurl/CMake/FindNGTCP2.cmake
index 3cbd408..02e7652 100644
--- a/Utilities/cmcurl/CMake/FindNGTCP2.cmake
+++ b/Utilities/cmcurl/CMake/FindNGTCP2.cmake
@@ -34,23 +34,28 @@
 #
 # Input variables:
 #
-# - `NGTCP2_INCLUDE_DIR`:   The ngtcp2 include directory.
-# - `NGTCP2_LIBRARY`:       Path to `ngtcp2` library.
+# - `NGTCP2_INCLUDE_DIR`:               The ngtcp2 include directory.
+# - `NGTCP2_LIBRARY`:                   Path to `ngtcp2` library.
+# - `NGTCP2_CRYPTO_BORINGSSL_LIBRARY`:  Path to `ngtcp2_crypto_boringssl` library.
+# - `NGTCP2_CRYPTO_GNUTLS_LIBRARY`:     Path to `ngtcp2_crypto_gnutls` library.
+# - `NGTCP2_CRYPTO_OSSL_LIBRARY`:       Path to `ngtcp2_crypto_ossl` library.
+# - `NGTCP2_CRYPTO_QUICTLS_LIBRARY`:    Path to `ngtcp2_crypto_quictls` library.
+# - `NGTCP2_CRYPTO_WOLFSSL_LIBRARY`:    Path to `ngtcp2_crypto_wolfssl` library.
 #
 # Result variables:
 #
-# - `NGTCP2_FOUND`:         System has ngtcp2.
-# - `NGTCP2_INCLUDE_DIRS`:  The ngtcp2 include directories.
-# - `NGTCP2_LIBRARIES`:     The ngtcp2 library names.
-# - `NGTCP2_LIBRARY_DIRS`:  The ngtcp2 library directories.
-# - `NGTCP2_PC_REQUIRES`:   The ngtcp2 pkg-config packages.
-# - `NGTCP2_CFLAGS`:        Required compiler flags.
-# - `NGTCP2_VERSION`:       Version of ngtcp2.
+# - `NGTCP2_FOUND`:                     System has ngtcp2.
+# - `NGTCP2_INCLUDE_DIRS`:              The ngtcp2 include directories.
+# - `NGTCP2_LIBRARIES`:                 The ngtcp2 library names.
+# - `NGTCP2_LIBRARY_DIRS`:              The ngtcp2 library directories.
+# - `NGTCP2_PC_REQUIRES`:               The ngtcp2 pkg-config packages.
+# - `NGTCP2_CFLAGS`:                    Required compiler flags.
+# - `NGTCP2_VERSION`:                   Version of ngtcp2.
 
 if(NGTCP2_FIND_COMPONENTS)
   set(_ngtcp2_crypto_backend "")
   foreach(_component IN LISTS NGTCP2_FIND_COMPONENTS)
-    if(_component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS|ossl)")
+    if(_component MATCHES "^(BoringSSL|GnuTLS|ossl|quictls|wolfSSL)")
       if(_ngtcp2_crypto_backend)
         message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
       endif()
diff --git a/Utilities/cmcurl/CMake/Macros.cmake b/Utilities/cmcurl/CMake/Macros.cmake
index e3a654b..710df70 100644
--- a/Utilities/cmcurl/CMake/Macros.cmake
+++ b/Utilities/cmcurl/CMake/Macros.cmake
@@ -65,6 +65,7 @@
   endif()
 endmacro()
 
+# Option for dependencies that accepts an 'AUTO' value, which enables the dependency if detected.
 macro(curl_dependency_option _option_name _find_name _desc_name)
   set(${_option_name} "AUTO" CACHE STRING "Build curl with ${_desc_name} support (AUTO, ON or OFF)")
   set_property(CACHE ${_option_name} PROPERTY STRINGS "AUTO" "ON" "OFF")
@@ -94,3 +95,80 @@
   set(SIZEOF_${_type} ${_size})
   set(SIZEOF_${_type}_CODE "#define SIZEOF_${_type} ${_size}")
 endmacro()
+
+# Internal: Recurse into target libraries and collect their include directories
+# and macro definitions.
+macro(curl_collect_target_options _target)
+  get_target_property(_val ${_target} INTERFACE_INCLUDE_DIRECTORIES)
+  if(_val)
+    list(APPEND _includes ${_val})
+  endif()
+  get_target_property(_val ${_target} INCLUDE_DIRECTORIES)
+  if(_val)
+    list(APPEND _includes ${_val})
+  endif()
+  get_target_property(_val ${_target} COMPILE_DEFINITIONS)
+  if(_val)
+    list(APPEND _definitions ${_val})
+  endif()
+  get_target_property(_val ${_target} LINK_LIBRARIES)
+  if(_val)
+    foreach(_lib IN LISTS _val)
+      if(TARGET "${_lib}")
+        curl_collect_target_options(${_lib})
+      endif()
+    endforeach()
+  endif()
+  unset(_val)
+endmacro()
+
+# Create a clang-tidy target for test targets
+macro(curl_add_clang_tidy_test_target _target_clang_tidy _target)
+  if(CURL_CLANG_TIDY)
+
+    set(_includes "")
+    set(_definitions "")
+
+    # Collect header directories and macro definitions applying to the directory
+    get_directory_property(_val INCLUDE_DIRECTORIES)
+    if(_val)
+      list(APPEND _includes ${_val})
+    endif()
+    get_directory_property(_val COMPILE_DEFINITIONS)
+    if(_val)
+      list(APPEND _definitions ${_val})
+    endif()
+    unset(_val)
+
+    # Collect header directories and macro definitions from lib dependencies
+    curl_collect_target_options(${_target})
+
+    list(REMOVE_ITEM _includes "")
+    string(REPLACE ";" ";-I" _includes ";${_includes}")
+    list(REMOVE_DUPLICATES _includes)
+
+    list(REMOVE_ITEM _definitions "")
+    string(REPLACE ";" ";-D" _definitions ";${_definitions}")
+    list(REMOVE_DUPLICATES _definitions)
+    list(SORT _definitions)  # Sort like CMake does
+
+    # Assemble source list
+    set(_sources "")
+    foreach(_source IN ITEMS ${ARGN})
+      if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_source}")  # if not in source tree
+        set(_source "${CMAKE_CURRENT_BINARY_DIR}/${_source}")  # look in the build tree, for generated files, e.g. lib1521.c
+      endif()
+      list(APPEND _sources "${_source}")
+    endforeach()
+
+    add_custom_target(${_target_clang_tidy} USES_TERMINAL
+      WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+      COMMAND ${CMAKE_C_CLANG_TIDY} ${_sources} -- ${_includes} ${_definitions}
+      DEPENDS ${_sources})
+    add_dependencies(tests-clang-tidy ${_target_clang_tidy})
+
+    unset(_includes)
+    unset(_definitions)
+    unset(_sources)
+  endif()
+endmacro()
diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake
index 26e9d82..9f59e0d 100644
--- a/Utilities/cmcurl/CMake/OtherTests.cmake
+++ b/Utilities/cmcurl/CMake/OtherTests.cmake
@@ -25,6 +25,7 @@
 include(CheckCSourceRuns)
 include(CheckTypeSize)
 
+# #include header if condition is true
 macro(curl_add_header_include _check _header)
   if(${_check})
     set(_source_epilogue "${_source_epilogue}
@@ -41,7 +42,7 @@
   if(WIN32)
     set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
     list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
-  elseif(HAVE_SYS_SOCKET_H)
+  else()
     set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
   endif()
   check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
@@ -52,8 +53,8 @@
 if(NOT WIN32)
   set(_source_epilogue "#undef inline")
   curl_add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
-  curl_add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
   check_c_source_compiles("${_source_epilogue}
+    #include <sys/socket.h>
     int main(void)
     {
       int flag = MSG_NOSIGNAL;
@@ -63,11 +64,13 @@
 endif()
 
 set(_source_epilogue "#undef inline")
-curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
 check_c_source_compiles("${_source_epilogue}
   #ifdef _MSC_VER
   #include <winsock2.h>
   #endif
+  #ifndef _WIN32
+  #include <sys/time.h>
+  #endif
   #include <time.h>
   int main(void)
   {
@@ -100,9 +103,11 @@
 endif()
 
 if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
-  set(_source_epilogue "#undef inline")
-  curl_add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
-  curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
+  set(_source_epilogue "#undef inline
+    #ifndef _WIN32
+    #include <sys/socket.h>
+    #include <sys/time.h>
+    #endif")
   curl_add_header_include(HAVE_NETDB_H "netdb.h")
   check_c_source_compiles("${_source_epilogue}
     int main(void)
@@ -143,8 +148,8 @@
 if(NOT WIN32 AND NOT DEFINED HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
   set(_source_epilogue "#undef inline")
   curl_add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
-  curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
   check_c_source_compiles("${_source_epilogue}
+    #include <sys/time.h>
     #include <time.h>
     int main(void)
     {
diff --git a/Utilities/cmcurl/CMake/PickyWarnings.cmake b/Utilities/cmcurl/CMake/PickyWarnings.cmake
index be26d05..7838f6f 100644
--- a/Utilities/cmcurl/CMake/PickyWarnings.cmake
+++ b/Utilities/cmcurl/CMake/PickyWarnings.cmake
@@ -316,8 +316,9 @@
     list(APPEND _picky "-wd4668")  # 'M' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' (in winbase.h)
     list(APPEND _picky "-wd4710")  # 'snprintf': function not inlined
     list(APPEND _picky "-wd4711")  # function 'A' selected for automatic inline expansion
-    list(APPEND _picky "-wd4746")  # volatile access of '<expression>' is subject to /volatile:<iso|ms> setting;
-                                   #   consider using __iso_volatile_load/store intrinsic functions (ARM64)
+    # volatile access of '<expression>' is subject to /volatile:<iso|ms> setting;
+    #   consider using __iso_volatile_load/store intrinsic functions (ARM64)
+    list(APPEND _picky "-wd4746")
     list(APPEND _picky "-wd4774")  # 'snprintf': format string expected in argument 3 is not a string literal
     list(APPEND _picky "-wd4820")  # 'A': 'N' bytes padding added after data member 'B'
     if(MSVC_VERSION GREATER_EQUAL 1900)
@@ -340,7 +341,7 @@
         list(APPEND _picky_tmp "-clang:${_ccopt}")
       endif()
     endforeach()
-    set("${_wlist}" ${_picky_tmp})
+    set("${_wlist}" ${_picky_tmp})  # cmake-lint: disable=C0103
   endforeach()
 endif()
 
diff --git a/Utilities/cmcurl/CMake/Utilities.cmake b/Utilities/cmcurl/CMake/Utilities.cmake
index ff2173f..335713c 100644
--- a/Utilities/cmcurl/CMake/Utilities.cmake
+++ b/Utilities/cmcurl/CMake/Utilities.cmake
@@ -51,3 +51,31 @@
   endforeach()
   message("::endgroup::")
 endfunction()
+
+# Dump all target properties
+function(curl_dumptargetprops _target)
+  if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND TARGET "${_target}")
+    execute_process(COMMAND "${CMAKE_COMMAND}" "--help-property-list" OUTPUT_VARIABLE _cmake_property_list)
+    string(REPLACE "\n" ";" _cmake_property_list "${_cmake_property_list}")
+    list(REMOVE_DUPLICATES _cmake_property_list)
+    list(REMOVE_ITEM _cmake_property_list "")
+    foreach(_prop IN LISTS _cmake_property_list)
+      if(_prop MATCHES "<CONFIG>")
+        foreach(_config IN ITEMS "DEBUG" "RELEASE" "MINSIZEREL" "RELWITHDEBINFO")
+          string(REPLACE "<CONFIG>" "${_config}" _propconfig "${_prop}")
+          get_property(_is_set TARGET "${_target}" PROPERTY "${_propconfig}" SET)
+          if(_is_set)
+            get_target_property(_val "${_target}" "${_propconfig}")
+            message("${_target}.${_propconfig} = '${_val}'")
+          endif()
+        endforeach()
+      else()
+        get_property(_is_set TARGET "${_target}" PROPERTY "${_prop}" SET)
+        if(_is_set)
+          get_target_property(_val "${_target}" "${_prop}")
+          message("${_target}.${_prop} = '${_val}'")
+        endif()
+      endif()
+    endforeach()
+  endif()
+endfunction()
diff --git a/Utilities/cmcurl/CMake/unix-cache.cmake b/Utilities/cmcurl/CMake/unix-cache.cmake
index f42ac5d..077fb7c 100644
--- a/Utilities/cmcurl/CMake/unix-cache.cmake
+++ b/Utilities/cmcurl/CMake/unix-cache.cmake
@@ -284,15 +284,12 @@
 set(HAVE_SYS_POLL_H 1)
 set(HAVE_SYS_RESOURCE_H 1)
 set(HAVE_SYS_SELECT_H 1)
-set(HAVE_SYS_SOCKET_H 1)
 if(CYGWIN OR
    CMAKE_SYSTEM_NAME STREQUAL "Linux")
   set(HAVE_SYS_SOCKIO_H 0)
 else()
   set(HAVE_SYS_SOCKIO_H 1)
 endif()
-set(HAVE_SYS_STAT_H 1)
-set(HAVE_SYS_TIME_H 1)
 set(HAVE_SYS_TYPES_H 1)
 set(HAVE_SYS_UN_H 1)
 if(CYGWIN)
diff --git a/Utilities/cmcurl/CMake/win32-cache.cmake b/Utilities/cmcurl/CMake/win32-cache.cmake
index 163a310..4fe9eb1 100644
--- a/Utilities/cmcurl/CMake/win32-cache.cmake
+++ b/Utilities/cmcurl/CMake/win32-cache.cmake
@@ -39,7 +39,6 @@
   set(HAVE_STDINT_H 1)  # detected by CMake internally in check_type_size()
   set(HAVE_STRINGS_H 1)  # wrapper to string.h
   set(HAVE_SYS_PARAM_H 1)
-  set(HAVE_SYS_TIME_H 1)
   set(HAVE_UNISTD_H 1)
   set(HAVE_UTIME_H 1)  # wrapper to sys/utime.h
 else()
@@ -50,7 +49,6 @@
   set(HAVE_OPENDIR 0)
   set(HAVE_STRINGS_H 0)
   set(HAVE_SYS_PARAM_H 0)
-  set(HAVE_SYS_TIME_H 0)
   set(HAVE_UTIME_H 0)
   if(MSVC)
     set(HAVE_UNISTD_H 0)
@@ -118,7 +116,6 @@
 set(HAVE_GLIBC_STRERROR_R 0)
 set(HAVE_GMTIME_R 0)
 set(HAVE_IFADDRS_H 0)
-set(HAVE_IF_NAMETOINDEX 0)
 set(HAVE_INET_NTOP 0)
 set(HAVE_INET_PTON 0)
 set(HAVE_IOCTLSOCKET 1)
@@ -171,9 +168,7 @@
 set(HAVE_SYS_POLL_H 0)
 set(HAVE_SYS_RESOURCE_H 0)
 set(HAVE_SYS_SELECT_H 0)
-set(HAVE_SYS_SOCKET_H 0)
 set(HAVE_SYS_SOCKIO_H 0)
-set(HAVE_SYS_STAT_H 1)
 set(HAVE_SYS_TYPES_H 1)
 set(HAVE_SYS_UN_H 0)
 set(HAVE_SYS_UTIME_H 1)
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index ddc975c..3d7c24b 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -11,7 +11,6 @@
 set(BUILD_STATIC_LIBS ON)
 set(BUILD_STATIC_CURL OFF)
 set(CURL_CA_SEARCH_SAFE OFF)
-set(CURL_USE_BEARSSL OFF)
 set(CURL_USE_GSASL OFF)
 set(CURL_USE_GSSAPI OFF)
 set(CURL_USE_LIBPSL OFF)
@@ -24,7 +23,6 @@
 set(CURL_USE_OPENSSL "${CMAKE_USE_OPENSSL}")
 set(CURL_USE_PKGCONFIG OFF)
 set(CURL_USE_SCHANNEL OFF)
-set(CURL_USE_SECTRANSP OFF)
 set(CURL_USE_WOLFSSH OFF)
 set(CURL_USE_WOLFSSL OFF)
 set(CURL_BROTLI "OFF" CACHE INTERNAL "Build curl with BROTLI support (AUTO, ON or OFF)")
@@ -90,7 +88,6 @@
 set(ENABLE_INET_PTON OFF CACHE INTERNAL "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc.")
 set(ENABLE_IPV6 ON CACHE INTERNAL "Enable curl IPv6 support detection")
 set(ENABLE_MANUAL OFF CACHE INTERNAL "No curl built-in manual")
-set(ENABLE_SERVER_DEBUG OFF)
 set(ENABLE_THREADED_RESOLVER OFF CACHE INTERNAL "No curl POSIX threaded DNS lookup")
 set(ENABLE_UNICODE OFF)
 set(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support")
@@ -121,23 +118,6 @@
 elseif(WIN32)
   set(CURL_USE_SCHANNEL ON)
   set(CURL_WINDOWS_SSPI ON)
-elseif(APPLE)
-  # Use OS X SSL/TLS native implementation if available on target version.
-  if(CMAKE_OSX_DEPLOYMENT_TARGET)
-    set(OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET})
-  else()
-    execute_process(
-      COMMAND sw_vers -productVersion
-      OUTPUT_VARIABLE OSX_VERSION
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      )
-  endif()
-  if(NOT OSX_VERSION VERSION_LESS 10.6 AND
-      CMAKE_C_COMPILER_ID MATCHES "GNU|LCC|Clang|AppleClang")
-    set(CURL_USE_SECTRANSP ON)
-  else()
-    set(CURL_USE_SECTRANSP OFF)
-  endif()
 endif()
 
 # Windows Vista and above have inet_pton, but this will link on
@@ -473,7 +453,6 @@
   message(WARNING "This curl build is Debug-enabled and insecure, do not use in production.")
 endif()
 option(ENABLE_CURLDEBUG "Enable TrackMemory debug feature" ${ENABLE_DEBUG})
-option(ENABLE_SERVER_DEBUG "Apply curl debug options to test servers" OFF)
 
 set(CURL_DEBUG_MACROS "")
 if(ENABLE_DEBUG)
@@ -484,15 +463,11 @@
 endif()
 
 if(0) # XXX(cmake): not needed for build within cmake
-option(CURL_TEST_BUNDLES "Build tests into single-binary bundles" OFF)
-
 option(CURL_CLANG_TIDY "Run the build through clang-tidy" OFF)
 if(CURL_CLANG_TIDY)
-  # clang-tidy is not looking into #included sources, thus not compatible with
-  # unity builds and test bundles.
-  set(CMAKE_UNITY_BUILD OFF)
-  set(CURL_TEST_BUNDLES OFF)
+  set(CMAKE_UNITY_BUILD OFF)  # clang-tidy is not looking into #included sources, thus not compatible with unity builds.
   set(_tidy_checks "")
+  list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.bzero")  # for FD_ZERO() (seen on macOS)
   list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.strcpy")
   list(APPEND _tidy_checks "-clang-analyzer-optin.performance.Padding")
   list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling")
@@ -574,6 +549,7 @@
   list(APPEND CURL_LIBS ${CARES_LIBRARIES})
   list(APPEND CURL_LIBDIRS ${CARES_LIBRARY_DIRS})
   list(APPEND LIBCURL_PC_REQUIRES_PRIVATE ${CARES_PC_REQUIRES})
+  include_directories(SYSTEM ${CARES_INCLUDE_DIRS})
   link_directories(${CARES_LIBRARY_DIRS})
   if(CARES_CFLAGS)
     string(APPEND CMAKE_C_FLAGS " ${CARES_CFLAGS}")
@@ -723,7 +699,7 @@
     DEPENDS "${PROJECT_SOURCE_DIR}/scripts/mk-ca-bundle.pl"
   )
   add_custom_target(curl-ca-firefox
-    COMMENT "generating a fresh ca-bundle.crt" VERBATIM USES_TERMINAL
+    COMMENT "Generating a fresh ca-bundle.crt" VERBATIM USES_TERMINAL
     COMMAND "${PERL_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/scripts/firefox-db2pem.sh" "lib/ca-bundle.crt"
     DEPENDS "${PROJECT_SOURCE_DIR}/scripts/firefox-db2pem.sh"
   )
@@ -813,10 +789,12 @@
     set(_win32_winsock "ws2_32")
   endif()
   set(_win32_crypt32 "crypt32")
+  set(_win32_secur32 "secur32")
 
   if(MINGW32CE)  # FIXME upstream: must specify the full path to avoid CMake converting "ws2" to "ws2.lib"
     set(_win32_winsock "${MINGW32CE_LIBRARY_DIR}/lib${_win32_winsock}.a")
     set(_win32_crypt32 "${MINGW32CE_LIBRARY_DIR}/lib${_win32_crypt32}.a")
+    set(_win32_secur32 "${MINGW32CE_LIBRARY_DIR}/lib${_win32_secur32}.a")
   endif()
 elseif(DOS)
   if(WATT_ROOT)
@@ -886,24 +864,18 @@
   set(_valid_default_ssl_backend FALSE)
 endif()
 
-if(APPLE)
-  cmake_dependent_option(CURL_USE_SECTRANSP "Enable Apple OS native SSL/TLS (Secure Transport)" OFF CURL_ENABLE_SSL OFF)
-endif()
 if(WIN32)
   cmake_dependent_option(CURL_USE_SCHANNEL "Enable Windows native SSL/TLS (Schannel)" OFF CURL_ENABLE_SSL OFF)
   option(CURL_WINDOWS_SSPI "Enable SSPI on Windows" ${CURL_USE_SCHANNEL})
 endif()
 cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
-cmake_dependent_option(CURL_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 cmake_dependent_option(CURL_USE_WOLFSSL "Enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 cmake_dependent_option(CURL_USE_GNUTLS "Enable GnuTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 cmake_dependent_option(CURL_USE_RUSTLS "Enable Rustls for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 
 if(WIN32 OR
-   CURL_USE_SECTRANSP OR
    CURL_USE_SCHANNEL OR
    CURL_USE_MBEDTLS OR
-   CURL_USE_BEARSSL OR
    CURL_USE_WOLFSSL OR
    CURL_USE_GNUTLS OR
    CURL_USE_RUSTLS)
@@ -922,10 +894,8 @@
 
 curl_count_true(_enabled_ssl_options_count
   CURL_USE_SCHANNEL
-  CURL_USE_SECTRANSP
   CURL_USE_OPENSSL
   CURL_USE_MBEDTLS
-  CURL_USE_BEARSSL
   CURL_USE_WOLFSSL
   CURL_USE_GNUTLS
   CURL_USE_RUSTLS
@@ -949,28 +919,6 @@
   set(USE_WINDOWS_SSPI ON)
 endif()
 
-if(CURL_USE_SECTRANSP)
-  set(_use_core_foundation_and_core_services ON)
-
-  find_library(SECURITY_FRAMEWORK NAMES "Security")
-  mark_as_advanced(SECURITY_FRAMEWORK)
-  if(NOT SECURITY_FRAMEWORK)
-    message(FATAL_ERROR "Security framework not found")
-  endif()
-  list(APPEND CURL_LIBS "-framework Security")
-
-  set(_ssl_enabled ON)
-  set(USE_SECTRANSP ON)
-
-  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "secure-transport")
-    set(_valid_default_ssl_backend TRUE)
-  endif()
-
-  if(0) # XXX(cmake): not needed for build within cmake
-  message(WARNING "Secure Transport does not support TLS 1.3.")
-  endif() # XXX(cmake): end
-endif()
-
 if(_use_core_foundation_and_core_services)
   find_library(COREFOUNDATION_FRAMEWORK NAMES "CoreFoundation")
   mark_as_advanced(COREFOUNDATION_FRAMEWORK)
@@ -1068,23 +1016,6 @@
   set(_curl_ca_bundle_supported TRUE)
 endif()
 
-if(CURL_USE_BEARSSL)
-  find_package(BearSSL REQUIRED)
-  set(_ssl_enabled ON)
-  set(USE_BEARSSL ON)
-  list(APPEND CURL_LIBS ${BEARSSL_LIBRARIES})
-  include_directories(SYSTEM ${BEARSSL_INCLUDE_DIRS})
-
-  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "bearssl")
-    set(_valid_default_ssl_backend TRUE)
-  endif()
-  set(_curl_ca_bundle_supported TRUE)
-
-  if(0) # XXX(cmake): not needed for build within cmake
-  message(WARNING "BearSSL does not support TLS 1.3.")
-  endif() # XXX(cmake): end
-endif()
-
 if(CURL_USE_WOLFSSL)
   find_package(WolfSSL REQUIRED)
   set(_ssl_enabled ON)
@@ -1889,6 +1820,23 @@
     # Windows XP is required for freeaddrinfo, getaddrinfo
     message(FATAL_ERROR "Building for Windows XP or newer is required.")
   endif()
+
+  # Pre-fill detection results based on target OS version
+  if(HAVE_WIN32_WINNT AND HAVE_WIN32_WINNT GREATER_EQUAL 0x0600 AND  # Windows Vista or newer
+     (MINGW OR MSVC) AND
+     NOT WINCE AND NOT WINDOWS_STORE)
+    set(HAVE_IF_NAMETOINDEX 1)
+  else()
+    set(HAVE_IF_NAMETOINDEX 0)
+  endif()
+  unset(HAVE_IF_NAMETOINDEX CACHE)
+endif()
+
+if(NOT WIN32)
+  list(APPEND CURL_INCLUDES "sys/socket.h")
+endif()
+if(NOT WIN32 OR MINGW)
+  list(APPEND CURL_INCLUDES "sys/time.h")
 endif()
 
 # Detect headers
@@ -1903,10 +1851,7 @@
 check_include_file("sys/poll.h"       HAVE_SYS_POLL_H)
 check_include_file("sys/resource.h"   HAVE_SYS_RESOURCE_H)
 check_include_file_concat_curl("sys/select.h"     HAVE_SYS_SELECT_H)
-check_include_file_concat_curl("sys/socket.h"     HAVE_SYS_SOCKET_H)
 check_include_file("sys/sockio.h"     HAVE_SYS_SOCKIO_H)
-check_include_file("sys/stat.h"       HAVE_SYS_STAT_H)
-check_include_file_concat_curl("sys/time.h"       HAVE_SYS_TIME_H)
 check_include_file_concat_curl("sys/types.h"      HAVE_SYS_TYPES_H)
 check_include_file("sys/un.h"         HAVE_SYS_UN_H)
 check_include_file_concat_curl("sys/utime.h"      HAVE_SYS_UTIME_H)  # sys/types.h (AmigaOS)
@@ -1948,10 +1893,9 @@
     HAVE_STDBOOL_H
     HAVE_STROPTS_H
     HAVE_SYS_IOCTL_H
-    HAVE_SYS_SOCKET_H
     HAVE_SYS_TYPES_H
     HAVE_UNISTD_H
-    )
+)
   if(${_variable})
     string(APPEND CURL_TEST_DEFINES " -D${_variable}")
   endif()
@@ -1971,6 +1915,9 @@
 # Apply to all feature checks
 if(WIN32)
   list(APPEND CMAKE_REQUIRED_LIBRARIES "${_win32_winsock}")
+  if(NOT WINCE AND NOT WINDOWS_STORE)
+    list(APPEND CMAKE_REQUIRED_LIBRARIES "iphlpapi")
+  endif()
 elseif(HAVE_LIBSOCKET)
   list(APPEND CMAKE_REQUIRED_LIBRARIES "socket")
 elseif(HAVE_LIBNETWORK)
@@ -2024,12 +1971,12 @@
 check_symbol_exists("ftruncate"       "unistd.h" HAVE_FTRUNCATE)
 check_symbol_exists("getpeername"     "${CURL_INCLUDES}" HAVE_GETPEERNAME)  # winsock2.h unistd.h proto/bsdsocket.h
 check_symbol_exists("getsockname"     "${CURL_INCLUDES}" HAVE_GETSOCKNAME)  # winsock2.h unistd.h proto/bsdsocket.h
+check_function_exists("if_nametoindex"  HAVE_IF_NAMETOINDEX)  # iphlpapi.h (Windows Vista+ non-UWP), net/if.h
 check_function_exists("getrlimit"       HAVE_GETRLIMIT)
 check_function_exists("setlocale"       HAVE_SETLOCALE)
 check_function_exists("setrlimit"       HAVE_SETRLIMIT)
 
 if(NOT WIN32)
-  check_function_exists("if_nametoindex"  HAVE_IF_NAMETOINDEX)  # iphlpapi.h (Windows non-UWP), net/if.h
   check_function_exists("realpath"        HAVE_REALPATH)
   check_function_exists("sched_yield"     HAVE_SCHED_YIELD)
   check_symbol_exists("strcasecmp"      "string.h" HAVE_STRCASECMP)
@@ -2076,7 +2023,7 @@
   list(APPEND CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
   check_type_size("ADDRESS_FAMILY" SIZEOF_ADDRESS_FAMILY)
   set(HAVE_ADDRESS_FAMILY ${HAVE_SIZEOF_ADDRESS_FAMILY})
-elseif(HAVE_SYS_SOCKET_H)
+else()
   list(APPEND CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
   check_type_size("sa_family_t" SIZEOF_SA_FAMILY_T)
   set(HAVE_SA_FAMILY_T ${HAVE_SIZEOF_SA_FAMILY_T})
@@ -2099,7 +2046,7 @@
     HAVE_BOOL_T
     STDC_HEADERS
     HAVE_ATOMIC
-    )
+)
   curl_internal_test(${_curl_test})
 endforeach()
 
@@ -2210,6 +2157,9 @@
 
 if(WIN32)
   list(APPEND CURL_LIBS "${_win32_winsock}")
+  if(NOT WINCE AND NOT WINDOWS_STORE)
+    list(APPEND CURL_LIBS "iphlpapi")
+  endif()
   if(NOT WINCE)
     list(APPEND CURL_LIBS "bcrypt")
   endif()
@@ -2230,6 +2180,9 @@
     endif()
     list(APPEND CURL_LIBS "${_win32_crypt32}")
   endif()
+  if(USE_WINDOWS_SSPI)
+    list(APPEND CURL_LIBS "${_win32_secur32}")
+  endif()
 endif()
 
 if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")  # MSVC but exclude clang-cl
@@ -2257,6 +2210,7 @@
 # (= regenerate it).
 function(curl_transform_makefile_inc _input_file _output_file)
   file(READ ${_input_file} _makefile_inc_text)
+  # cmake-lint: disable=W0106
   string(REPLACE "$(top_srcdir)"   "\${PROJECT_SOURCE_DIR}" _makefile_inc_text ${_makefile_inc_text})
   string(REPLACE "$(top_builddir)" "\${PROJECT_BINARY_DIR}" _makefile_inc_text ${_makefile_inc_text})
 
@@ -2345,7 +2299,6 @@
    (USE_OPENSSL OR
     USE_MBEDTLS OR
     USE_GNUTLS OR
-    USE_SECTRANSP OR
     USE_WIN32_CRYPTO OR
     (USE_WOLFSSL AND HAVE_WOLFSSL_DES_ECB_ENCRYPT)))
   set(_use_curl_ntlm_core ON)
@@ -2426,8 +2379,7 @@
 curl_add_if("HTTP3"         USE_NGTCP2 OR USE_QUICHE OR USE_MSH3 OR USE_OPENSSL_QUIC)
 curl_add_if("MultiSSL"      CURL_WITH_MULTI_SSL)
 curl_add_if("HTTPS-proxy"   NOT CURL_DISABLE_PROXY AND _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS
-                            OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
-                            USE_MBEDTLS OR USE_SECTRANSP OR
+                            OR USE_SCHANNEL OR USE_RUSTLS OR USE_MBEDTLS OR
                             (USE_WOLFSSL AND HAVE_WOLFSSL_BIO_NEW)))
 curl_add_if("Unicode"       ENABLE_UNICODE)
 curl_add_if("threadsafe"    HAVE_ATOMIC OR
@@ -2456,9 +2408,7 @@
 curl_add_if("Schannel"         _ssl_enabled AND USE_SCHANNEL)
 curl_add_if("${_openssl}"      _ssl_enabled AND USE_OPENSSL AND OPENSSL_VERSION VERSION_LESS 3.0.0)
 curl_add_if("${_openssl} v3+"  _ssl_enabled AND USE_OPENSSL AND OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
-curl_add_if("Secure Transport" _ssl_enabled AND USE_SECTRANSP)
 curl_add_if("mbedTLS"          _ssl_enabled AND USE_MBEDTLS)
-curl_add_if("BearSSL"          _ssl_enabled AND USE_BEARSSL)
 curl_add_if("wolfSSL"          _ssl_enabled AND USE_WOLFSSL)
 curl_add_if("GnuTLS"           _ssl_enabled AND USE_GNUTLS)
 curl_add_if("rustls"           _ssl_enabled AND USE_RUSTLS)
diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h
index d769108..404c001 100644
--- a/Utilities/cmcurl/include/curl/curl.h
+++ b/Utilities/cmcurl/include/curl/curl.h
@@ -158,11 +158,11 @@
   CURLSSLBACKEND_POLARSSL               CURL_DEPRECATED(7.69.0, "") = 6,
   CURLSSLBACKEND_WOLFSSL = 7,
   CURLSSLBACKEND_SCHANNEL = 8,
-  CURLSSLBACKEND_SECURETRANSPORT = 9,
+  CURLSSLBACKEND_SECURETRANSPORT        CURL_DEPRECATED(8.15.0, "") = 9,
   CURLSSLBACKEND_AXTLS                  CURL_DEPRECATED(7.61.0, "") = 10,
   CURLSSLBACKEND_MBEDTLS = 11,
   CURLSSLBACKEND_MESALINK               CURL_DEPRECATED(7.82.0, "") = 12,
-  CURLSSLBACKEND_BEARSSL = 13,
+  CURLSSLBACKEND_BEARSSL                CURL_DEPRECATED(8.15.0, "") = 13,
   CURLSSLBACKEND_RUSTLS = 14
 } curl_sslbackend;
 
@@ -645,20 +645,7 @@
   CURLE_UNRECOVERABLE_POLL,      /* 99 - poll/select returned fatal error */
   CURLE_TOO_LARGE,               /* 100 - a value/data met its maximum */
   CURLE_ECH_REQUIRED,            /* 101 - ECH tried but failed */
-  CURL_LAST, /* never use! */
-
-  CURLE_RESERVED115 = 115,       /* 115-126 - used in tests */
-  CURLE_RESERVED116 = 116,
-  CURLE_RESERVED117 = 117,
-  CURLE_RESERVED118 = 118,
-  CURLE_RESERVED119 = 119,
-  CURLE_RESERVED120 = 120,
-  CURLE_RESERVED121 = 121,
-  CURLE_RESERVED122 = 122,
-  CURLE_RESERVED123 = 123,
-  CURLE_RESERVED124 = 124,
-  CURLE_RESERVED125 = 125,
-  CURLE_RESERVED126 = 126
+  CURL_LAST /* never use! */
 } CURLcode;
 
 #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
@@ -943,31 +930,31 @@
    have introduced work-arounds for this flaw but those work-arounds sometimes
    make the SSL communication fail. To regain functionality with those broken
    servers, a user can this way allow the vulnerability back. */
-#define CURLSSLOPT_ALLOW_BEAST (1<<0)
+#define CURLSSLOPT_ALLOW_BEAST (1L<<0)
 
 /* - NO_REVOKE tells libcurl to disable certificate revocation checks for those
    SSL backends where such behavior is present. */
-#define CURLSSLOPT_NO_REVOKE (1<<1)
+#define CURLSSLOPT_NO_REVOKE (1L<<1)
 
 /* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain
    if possible. The OpenSSL backend has this ability. */
-#define CURLSSLOPT_NO_PARTIALCHAIN (1<<2)
+#define CURLSSLOPT_NO_PARTIALCHAIN (1L<<2)
 
 /* - REVOKE_BEST_EFFORT tells libcurl to ignore certificate revocation offline
    checks and ignore missing revocation list for those SSL backends where such
    behavior is present. */
-#define CURLSSLOPT_REVOKE_BEST_EFFORT (1<<3)
+#define CURLSSLOPT_REVOKE_BEST_EFFORT (1L<<3)
 
 /* - CURLSSLOPT_NATIVE_CA tells libcurl to use standard certificate store of
    operating system. Currently implemented under MS-Windows. */
-#define CURLSSLOPT_NATIVE_CA (1<<4)
+#define CURLSSLOPT_NATIVE_CA (1L<<4)
 
 /* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use
    a client certificate for authentication. (Schannel) */
-#define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5)
+#define CURLSSLOPT_AUTO_CLIENT_CERT (1L<<5)
 
 /* If possible, send data using TLS 1.3 early data */
-#define CURLSSLOPT_EARLYDATA (1<<6)
+#define CURLSSLOPT_EARLYDATA (1L<<6)
 
 /* The default connection attempt delay in milliseconds for happy eyeballs.
    CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
@@ -1967,7 +1954,8 @@
   CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232),
 
   /* Set if we should enable TLS false start. */
-  CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233),
+  CURLOPTDEPRECATED(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233,
+                    8.15.0, "Has no function"),
 
   /* Do not squash dot-dot sequences */
   CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234),
@@ -2301,10 +2289,10 @@
   /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
      name resolves addresses using more than one IP protocol version, this
      option might be handy to force libcurl to use a specific IP version. */
-#define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP
+#define CURL_IPRESOLVE_WHATEVER 0L /* default, uses addresses to all IP
                                      versions that your system allows */
-#define CURL_IPRESOLVE_V4       1 /* uses only IPv4 addresses/connections */
-#define CURL_IPRESOLVE_V6       2 /* uses only IPv6 addresses/connections */
+#define CURL_IPRESOLVE_V4       1L /* uses only IPv4 addresses/connections */
+#define CURL_IPRESOLVE_V6       2L /* uses only IPv6 addresses/connections */
 
   /* Convenient "aliases" */
 #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h
index cce4b20..e8c81e2 100644
--- a/Utilities/cmcurl/include/curl/curlver.h
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@ -32,13 +32,13 @@
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "8.14.1"
+#define LIBCURL_VERSION "8.15.0"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 14
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 15
+#define LIBCURL_VERSION_PATCH 0
 
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -59,7 +59,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x080e01
+#define LIBCURL_VERSION_NUM 0x080f00
 
 /*
  * This is the date and time when the full source package was created. The
diff --git a/Utilities/cmcurl/include/curl/system.h b/Utilities/cmcurl/include/curl/system.h
index f1c2719..ebcdc5e 100644
--- a/Utilities/cmcurl/include/curl/system.h
+++ b/Utilities/cmcurl/include/curl/system.h
@@ -329,7 +329,7 @@
    defined(__ppc__) || defined(__powerpc__) || defined(__arm__) ||      \
    defined(__sparc__) || defined(__mips__) || defined(__sh__) ||        \
    defined(__XTENSA__) ||                                               \
-   (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4)  ||               \
+   (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) ||                \
    (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L))
 #    define CURL_TYPEOF_CURL_OFF_T     long long
 #    define CURL_FORMAT_CURL_OFF_T     "lld"
@@ -357,11 +357,11 @@
 
 #else
 /* generic "safe guess" on old 32-bit style */
-#  define CURL_TYPEOF_CURL_OFF_T     long
-#  define CURL_FORMAT_CURL_OFF_T     "ld"
-#  define CURL_FORMAT_CURL_OFF_TU    "lu"
-#  define CURL_SUFFIX_CURL_OFF_T     L
-#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 #endif
 
@@ -399,52 +399,4 @@
   typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
 #endif
 
-/*
- * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
- * these to be visible and exported by the external libcurl interface API,
- * while also making them visible to the library internals, simply including
- * curl_setup.h, without actually needing to include curl.h internally.
- * If some day this section would grow big enough, all this should be moved
- * to its own header file.
- */
-
-/*
- * Figure out if we can use the ## preprocessor operator, which is supported
- * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
- * or  __cplusplus so we need to carefully check for them too.
- */
-
-#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
-  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
-  defined(__POCC__) || defined(__HIGHC__) || \
-  defined(__ILEC400__)
-  /* This compiler is believed to have an ISO compatible preprocessor */
-#define CURL_ISOCPP
-#else
-  /* This compiler is believed NOT to have an ISO compatible preprocessor */
-#undef CURL_ISOCPP
-#endif
-
-/*
- * Macros for minimum-width signed and unsigned curl_off_t integer constants.
- */
-
-#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
-#  define CURLINC_OFF_T_C_HLPR2(x) x
-#  define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x)
-#  define CURL_OFF_T_C(Val)  CURLINC_OFF_T_C_HLPR1(Val) ## \
-                             CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
-#  define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \
-                             CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
-#else
-#  ifdef CURL_ISOCPP
-#    define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
-#  else
-#    define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
-#  endif
-#  define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix)
-#  define CURL_OFF_T_C(Val)  CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
-#  define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
-#endif
-
 #endif /* CURLINC_SYSTEM_H */
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index 6a0798d..da39728 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -29,7 +29,7 @@
 
 configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
 
-# Get 'CSOURCES', 'HHEADERS' variables
+# Get CSOURCES, HHEADERS, LIB_RCFILES variables
 curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 
@@ -41,10 +41,6 @@
   "${PROJECT_BINARY_DIR}/lib"        # for "curl_config.h"
 )
 
-if(USE_ARES)
-  include_directories(SYSTEM ${CARES_INCLUDE_DIRS})
-endif()
-
 #-----------------------------------------------------------------------------
 # XXX(cmake): begin cmake-specific curl code
 unset(LIBCURL_OUTPUT_NAME CACHE)
@@ -85,23 +81,21 @@
 #-----------------------------------------------------------------------------
 
 if(CURL_BUILD_TESTING)
-  add_library(
-    curlu  # special libcurlu library just for unittests
-    STATIC
-    EXCLUDE_FROM_ALL
-    ${HHEADERS} ${CSOURCES}
-  )
+  # special libcurlu library just for unittests
+  add_library(curlu STATIC EXCLUDE_FROM_ALL ${HHEADERS} ${CSOURCES})
   target_compile_definitions(curlu PUBLIC "CURL_STATICLIB" "UNITTESTS")
   target_link_libraries(curlu PRIVATE ${CURL_LIBS})
   # There is plenty of parallelism when building the testdeps target.
   # Override the curlu batch size with the maximum to optimize performance.
-  set_target_properties(curlu PROPERTIES UNITY_BUILD_BATCH_SIZE 0)
-endif()
+  set_target_properties(curlu PROPERTIES UNITY_BUILD_BATCH_SIZE 0 C_CLANG_TIDY "")
 
-if(ENABLE_CURLDEBUG)
-  # We must compile this source separately to avoid memdebug.h redefinitions
-  # applying to it.
-  set_source_files_properties("memdebug.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+  add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h"
+    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
+    COMMAND ${PERL_EXECUTABLE} "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos"
+      ${CSOURCES} > "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h"
+    DEPENDS "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos" ${CSOURCES}
+    VERBATIM)
+  add_custom_target(curlu-unitprotos ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h")
 endif()
 
 ## Library definition
@@ -220,7 +214,7 @@
   add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
   if(WIN32)
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "dllmain.c")
-    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "libcurl.rc")
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES ${LIB_RCFILES})
     if(CURL_HIDES_PRIVATE_SYMBOLS)
       set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${PROJECT_SOURCE_DIR}/lib/libcurl.def")
     endif()
@@ -256,6 +250,7 @@
     CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
     CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
     CMAKE_SYSTEM_NAME STREQUAL "Haiku" OR
+    CMAKE_SYSTEM_NAME STREQUAL "OHOS" OR  # OpenHarmony
     CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
     set(_soversion_default TRUE)
   else()
@@ -266,7 +261,7 @@
   option(CURL_LIBCURL_VERSIONED_SYMBOLS "Enable libcurl versioned symbols" OFF)
 
   if(CURL_LIBCURL_SOVERSION OR CURL_LIBCURL_VERSIONED_SYMBOLS)
-    # Get 'VERSIONCHANGE', 'VERSIONADD', 'VERSIONDEL', 'VERSIONINFO' variables
+    # Get VERSIONCHANGE, VERSIONADD, VERSIONDEL, VERSIONINFO variables
     curl_transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
     include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
 
@@ -290,8 +285,6 @@
         set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "OPENSSL_")
       elseif(CURL_USE_MBEDTLS)
         set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "MBEDTLS_")
-      elseif(CURL_USE_BEARSSL)
-        set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "BEARSSL_")
       elseif(CURL_USE_WOLFSSL)
         set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "WOLFSSL_")
       elseif(CURL_USE_GNUTLS)
diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc
index b384e09..257e104 100644
--- a/Utilities/cmcurl/lib/Makefile.inc
+++ b/Utilities/cmcurl/lib/Makefile.inc
@@ -21,10 +21,12 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
+# Shared between CMakeLists.txt and Makefile.am
 
 LIB_CURLX_CFILES = \
   curlx/base64.c   \
   curlx/dynbuf.c   \
+  curlx/inet_ntop.c \
   curlx/inet_pton.c \
   curlx/multibyte.c \
   curlx/nonblock.c \
@@ -32,13 +34,16 @@
   curlx/timediff.c \
   curlx/timeval.c  \
   curlx/version_win32.c \
+  curlx/wait.c     \
   curlx/warnless.c \
   curlx/winapi.c
 
 LIB_CURLX_HFILES = \
+  curlx/binmode.h  \
   curlx/base64.h   \
   curlx/curlx.h    \
   curlx/dynbuf.h   \
+  curlx/inet_ntop.h \
   curlx/inet_pton.h \
   curlx/multibyte.h \
   curlx/nonblock.h \
@@ -46,6 +51,7 @@
   curlx/timediff.h \
   curlx/timeval.h  \
   curlx/version_win32.h \
+  curlx/wait.h     \
   curlx/warnless.h \
   curlx/winapi.h
 
@@ -69,7 +75,6 @@
   vauth/vauth.h
 
 LIB_VTLS_CFILES =           \
-  vtls/bearssl.c            \
   vtls/cipher_suite.c       \
   vtls/gtls.c               \
   vtls/hostcheck.c          \
@@ -80,7 +85,6 @@
   vtls/rustls.c             \
   vtls/schannel.c           \
   vtls/schannel_verify.c    \
-  vtls/sectransp.c          \
   vtls/vtls.c               \
   vtls/vtls_scache.c        \
   vtls/vtls_spack.c         \
@@ -88,7 +92,6 @@
   vtls/x509asn1.c
 
 LIB_VTLS_HFILES =           \
-  vtls/bearssl.h            \
   vtls/cipher_suite.h       \
   vtls/gtls.h               \
   vtls/hostcheck.h          \
@@ -99,7 +102,6 @@
   vtls/rustls.h             \
   vtls/schannel.h           \
   vtls/schannel_int.h       \
-  vtls/sectransp.h          \
   vtls/vtls.h               \
   vtls/vtls_int.h           \
   vtls/vtls_scache.h        \
@@ -208,7 +210,6 @@
   idn.c              \
   if2ip.c            \
   imap.c             \
-  inet_ntop.c        \
   krb5.c             \
   ldap.c             \
   llist.c            \
@@ -345,7 +346,6 @@
   idn.h              \
   if2ip.h            \
   imap.h             \
-  inet_ntop.h        \
   llist.h            \
   macos.h            \
   memdebug.h         \
diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c
index 602ef61..59476d7 100644
--- a/Utilities/cmcurl/lib/altsvc.c
+++ b/Utilities/cmcurl/lib/altsvc.c
@@ -32,7 +32,6 @@
 #include "urldata.h"
 #include "altsvc.h"
 #include "curl_get_line.h"
-#include "strcase.h"
 #include "parsedate.h"
 #include "sendf.h"
 #include "curlx/warnless.h"
@@ -416,7 +415,7 @@
   if(hlen != clen)
     /* they cannot match if they have different lengths */
     return FALSE;
-  return strncasecompare(host, check, hlen);
+  return curl_strnequal(host, check, hlen);
 }
 
 /* altsvc_flush() removes all alternatives for this source origin from the
@@ -487,8 +486,7 @@
   DEBUGASSERT(asi);
 
   /* initial check for "clear" */
-  if(!curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, ';') &&
-     !curlx_str_single(&p, ';')) {
+  if(!curlx_str_cspn(&p, &alpn, ";\n\r")) {
     curlx_str_trimblanks(&alpn);
     /* "clear" is a magic keyword */
     if(curlx_str_casecompare(&alpn, "clear")) {
@@ -666,4 +664,8 @@
   return FALSE;
 }
 
+#if defined(DEBUGBUILD) || defined(UNITTESTS)
+#undef time
+#endif
+
 #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
index 10f870a..007f1d7 100644
--- a/Utilities/cmcurl/lib/asyn-ares.c
+++ b/Utilities/cmcurl/lib/asyn-ares.c
@@ -48,6 +48,7 @@
 #endif
 
 #include "urldata.h"
+#include "cfilters.h"
 #include "sendf.h"
 #include "hostip.h"
 #include "hash.h"
@@ -451,8 +452,7 @@
   /* Operation complete, if the lookup was successful we now have the entry
      in the cache. */
   data->state.async.done = TRUE;
-  if(entry)
-    *entry = data->state.async.dns;
+  *entry = data->state.async.dns;
 
   if(result)
     ares_cancel(ares->channel);
@@ -758,7 +758,8 @@
                  (pf == PF_UNSPEC) ? "A+AAAA" :
                  ((pf == PF_INET) ? "A" : "AAAA"));
     hints.ai_family = pf;
-    hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+    hints.ai_socktype =
+      (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
       SOCK_STREAM : SOCK_DGRAM;
     /* Since the service is a numerical one, set the hint flags
      * accordingly to save a call to getservbyname in inside C-Ares
diff --git a/Utilities/cmcurl/lib/asyn-thrdd.c b/Utilities/cmcurl/lib/asyn-thrdd.c
index 9cd25dc..1ede868 100644
--- a/Utilities/cmcurl/lib/asyn-thrdd.c
+++ b/Utilities/cmcurl/lib/asyn-thrdd.c
@@ -55,13 +55,13 @@
 #endif
 
 #include "urldata.h"
+#include "cfilters.h"
 #include "sendf.h"
 #include "hostip.h"
 #include "hash.h"
 #include "share.h"
 #include "url.h"
 #include "multiif.h"
-#include "inet_ntop.h"
 #include "curl_threads.h"
 #include "strdup.h"
 
@@ -423,6 +423,7 @@
   data->state.async.done = FALSE;
   data->state.async.port = port;
   data->state.async.ip_version = ip_version;
+  free(data->state.async.hostname);
   data->state.async.hostname = strdup(hostname);
   if(!data->state.async.hostname)
     goto err_exit;
@@ -741,7 +742,8 @@
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+  hints.ai_socktype =
+    (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
     SOCK_STREAM : SOCK_DGRAM;
 
   /* fire up a new resolver thread! */
diff --git a/Utilities/cmcurl/lib/bufq.c b/Utilities/cmcurl/lib/bufq.c
index 724d62f..8783619 100644
--- a/Utilities/cmcurl/lib/bufq.c
+++ b/Utilities/cmcurl/lib/bufq.c
@@ -86,44 +86,26 @@
   }
 }
 
-static size_t chunk_unwrite(struct buf_chunk *chunk, size_t len)
-{
-  size_t n = chunk->w_offset - chunk->r_offset;
-  DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
-  if(!n) {
-    return 0;
-  }
-  else if(n <= len) {
-    chunk->r_offset = chunk->w_offset = 0;
-    return n;
-  }
-  else {
-    chunk->w_offset -= len;
-    return len;
-  }
-}
-
-static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
-                            Curl_bufq_reader *reader,
-                            void *reader_ctx, CURLcode *err)
+static CURLcode chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
+                             Curl_bufq_reader *reader,
+                             void *reader_ctx, size_t *pnread)
 {
   unsigned char *p = &chunk->x.data[chunk->w_offset];
   size_t n = chunk->dlen - chunk->w_offset; /* free amount */
-  ssize_t nread;
+  CURLcode result;
 
+  *pnread = 0;
   DEBUGASSERT(chunk->dlen >= chunk->w_offset);
-  if(!n) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
+  if(!n)
+    return CURLE_AGAIN;
   if(max_len && n > max_len)
     n = max_len;
-  nread = reader(reader_ctx, p, n, err);
-  if(nread > 0) {
-    DEBUGASSERT((size_t)nread <= n);
-    chunk->w_offset += nread;
+  result = reader(reader_ctx, p, n, pnread);
+  if(!result) {
+    DEBUGASSERT(*pnread <= n);
+    chunk->w_offset += *pnread;
   }
-  return nread;
+  return result;
 }
 
 static void chunk_peek(const struct buf_chunk *chunk,
@@ -357,49 +339,6 @@
   }
 }
 
-static struct buf_chunk *chunk_prev(struct buf_chunk *head,
-                                    struct buf_chunk *chunk)
-{
-  while(head) {
-    if(head == chunk)
-      return NULL;
-    if(head->next == chunk)
-      return head;
-    head = head->next;
-  }
-  return NULL;
-}
-
-static void prune_tail(struct bufq *q)
-{
-  struct buf_chunk *chunk;
-
-  while(q->tail && chunk_is_empty(q->tail)) {
-    chunk = q->tail;
-    q->tail = chunk_prev(q->head, chunk);
-    if(q->tail)
-      q->tail->next = NULL;
-    if(q->head == chunk)
-      q->head = q->tail;
-    if(q->pool) {
-      bufcp_put(q->pool, chunk);
-      --q->chunk_count;
-    }
-    else if((q->chunk_count > q->max_chunks) ||
-       (q->opts & BUFQ_OPT_NO_SPARES)) {
-      /* SOFT_LIMIT allowed us more than max. free spares until
-       * we are at max again. Or free them if we are configured
-       * to not use spares. */
-      free(chunk);
-      --q->chunk_count;
-    }
-    else {
-      chunk->next = q->spare;
-      q->spare = chunk;
-    }
-  }
-}
-
 static struct buf_chunk *get_non_full_tail(struct bufq *q)
 {
   struct buf_chunk *chunk;
@@ -421,90 +360,60 @@
   return chunk;
 }
 
-ssize_t Curl_bufq_write(struct bufq *q,
-                        const unsigned char *buf, size_t len,
-                        CURLcode *err)
+CURLcode Curl_bufq_write(struct bufq *q,
+                         const unsigned char *buf, size_t len,
+                         size_t *pnwritten)
 {
   struct buf_chunk *tail;
-  ssize_t nwritten = 0;
   size_t n;
 
   DEBUGASSERT(q->max_chunks > 0);
+  *pnwritten = 0;
   while(len) {
     tail = get_non_full_tail(q);
     if(!tail) {
-      if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT)) {
-        *err = CURLE_OUT_OF_MEMORY;
-        return -1;
-      }
+      if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT))
+        /* should have gotten a tail, but did not */
+        return CURLE_OUT_OF_MEMORY;
       break;
     }
     n = chunk_append(tail, buf, len);
     if(!n)
       break;
-    nwritten += n;
+    *pnwritten += n;
     buf += n;
     len -= n;
   }
-  if(nwritten == 0 && len) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
-  *err = CURLE_OK;
-  return nwritten;
+  return (!*pnwritten && len) ? CURLE_AGAIN : CURLE_OK;
 }
 
 CURLcode Curl_bufq_cwrite(struct bufq *q,
                           const char *buf, size_t len,
                           size_t *pnwritten)
 {
-  ssize_t n;
-  CURLcode result;
-  n = Curl_bufq_write(q, (const unsigned char *)buf, len, &result);
-  *pnwritten = (n < 0) ? 0 : (size_t)n;
-  return result;
+  return Curl_bufq_write(q, (const unsigned char *)buf, len, pnwritten);
 }
 
-CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len)
+CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
+                        size_t *pnread)
 {
-  while(len && q->tail) {
-    len -= chunk_unwrite(q->tail, len);
-    prune_tail(q);
-  }
-  return len ? CURLE_AGAIN : CURLE_OK;
-}
-
-ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
-                       CURLcode *err)
-{
-  ssize_t nread = 0;
-  size_t n;
-
-  *err = CURLE_OK;
+  *pnread = 0;
   while(len && q->head) {
-    n = chunk_read(q->head, buf, len);
+    size_t n = chunk_read(q->head, buf, len);
     if(n) {
-      nread += n;
+      *pnread += n;
       buf += n;
       len -= n;
     }
     prune_head(q);
   }
-  if(nread == 0) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
-  return nread;
+  return (!*pnread) ? CURLE_AGAIN : CURLE_OK;
 }
 
 CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
                          size_t *pnread)
 {
-  ssize_t n;
-  CURLcode result;
-  n = Curl_bufq_read(q, (unsigned char *)buf, len, &result);
-  *pnread = (n < 0) ? 0 : (size_t)n;
-  return result;
+  return Curl_bufq_read(q, (unsigned char *)buf, len, pnread);
 }
 
 bool Curl_bufq_peek(struct bufq *q,
@@ -556,156 +465,139 @@
   }
 }
 
-ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
-                       void *writer_ctx, CURLcode *err)
+CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
+                        void *writer_ctx, size_t *pwritten)
 {
   const unsigned char *buf;
   size_t blen;
-  ssize_t nwritten = 0;
+  CURLcode result = CURLE_OK;
 
+  *pwritten = 0;
   while(Curl_bufq_peek(q, &buf, &blen)) {
-    ssize_t chunk_written;
+    size_t chunk_written;
 
-    chunk_written = writer(writer_ctx, buf, blen, err);
-    if(chunk_written < 0) {
-      if(!nwritten || *err != CURLE_AGAIN) {
-        /* blocked on first write or real error, fail */
-        nwritten = -1;
+    result = writer(writer_ctx, buf, blen, &chunk_written);
+    if(result) {
+      if((result == CURLE_AGAIN) && *pwritten) {
+        /* blocked on subsequent write, report success */
+        result = CURLE_OK;
       }
       break;
     }
     if(!chunk_written) {
-      if(!nwritten) {
+      if(!*pwritten) {
         /* treat as blocked */
-        *err = CURLE_AGAIN;
-        nwritten = -1;
+        result = CURLE_AGAIN;
       }
       break;
     }
-    Curl_bufq_skip(q, (size_t)chunk_written);
-    nwritten += chunk_written;
+    *pwritten += chunk_written;
+    Curl_bufq_skip(q, chunk_written);
   }
-  return nwritten;
+  return result;
 }
 
-ssize_t Curl_bufq_write_pass(struct bufq *q,
-                             const unsigned char *buf, size_t len,
-                             Curl_bufq_writer *writer, void *writer_ctx,
-                             CURLcode *err)
+CURLcode Curl_bufq_write_pass(struct bufq *q,
+                              const unsigned char *buf, size_t len,
+                              Curl_bufq_writer *writer, void *writer_ctx,
+                              size_t *pwritten)
 {
-  ssize_t nwritten = 0, n;
+  CURLcode result = CURLE_OK;
+  size_t n;
 
-  *err = CURLE_OK;
+  *pwritten = 0;
   while(len) {
     if(Curl_bufq_is_full(q)) {
       /* try to make room in case we are full */
-      n = Curl_bufq_pass(q, writer, writer_ctx, err);
-      if(n < 0) {
-        if(*err != CURLE_AGAIN) {
+      result = Curl_bufq_pass(q, writer, writer_ctx, &n);
+      if(result) {
+        if(result != CURLE_AGAIN) {
           /* real error, fail */
-          return -1;
+          return result;
         }
         /* would block, bufq is full, give up */
         break;
       }
     }
 
-    /* Add whatever is remaining now to bufq */
-    n = Curl_bufq_write(q, buf, len, err);
-    if(n < 0) {
-      if(*err != CURLE_AGAIN) {
+    /* Add to bufq as much as there is room for */
+    result = Curl_bufq_write(q, buf, len, &n);
+    if(result) {
+      if(result != CURLE_AGAIN)
         /* real error, fail */
-        return -1;
-      }
-      /* no room in bufq */
-      break;
+        return result;
+      if((result == CURLE_AGAIN) && *pwritten)
+        /* we did write successfully before */
+        result = CURLE_OK;
+      return result;
     }
-    /* edge case of writer returning 0 (and len is >0)
-     * break or we might enter an infinite loop here */
-    if(n == 0)
+    else if(n == 0)
+      /* edge case of writer returning 0 (and len is >0)
+       * break or we might enter an infinite loop here */
       break;
 
-    /* Maybe only part of `data` has been added, continue to loop */
-    buf += (size_t)n;
-    len -= (size_t)n;
-    nwritten += (size_t)n;
+    /* Track what we added to bufq */
+    buf += n;
+    len -= n;
+    *pwritten += n;
   }
 
-  if(!nwritten && len) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
-  *err = CURLE_OK;
-  return nwritten;
+  return (!*pwritten && len) ? CURLE_AGAIN : CURLE_OK;
 }
 
-ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
-                       Curl_bufq_reader *reader, void *reader_ctx,
-                       CURLcode *err)
+CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len,
+                        Curl_bufq_reader *reader, void *reader_ctx,
+                        size_t *pnread)
 {
   struct buf_chunk *tail = NULL;
-  ssize_t nread;
 
-  *err = CURLE_AGAIN;
+  *pnread = 0;
   tail = get_non_full_tail(q);
   if(!tail) {
-    if(q->chunk_count < q->max_chunks) {
-      *err = CURLE_OUT_OF_MEMORY;
-      return -1;
-    }
+    if(q->chunk_count < q->max_chunks)
+      return CURLE_OUT_OF_MEMORY;
     /* full, blocked */
-    *err = CURLE_AGAIN;
-    return -1;
+    return CURLE_AGAIN;
   }
 
-  nread = chunk_slurpn(tail, max_len, reader, reader_ctx, err);
-  if(nread < 0) {
-    return -1;
-  }
-  else if(nread == 0) {
-    /* eof */
-    *err = CURLE_OK;
-  }
-  return nread;
+  return chunk_slurpn(tail, max_len, reader, reader_ctx, pnread);
 }
 
 /**
  * Read up to `max_len` bytes and append it to the end of the buffer queue.
  * if `max_len` is 0, no limit is imposed and the call behaves exactly
  * the same as `Curl_bufq_slurp()`.
- * Returns the total amount of buf read (may be 0) or -1 on other
- * reader errors.
- * Note that even in case of a -1 chunks may have been read and
+ * Returns the total amount of buf read (may be 0) in `pnread` or error
+ * Note that even in case of an error chunks may have been read and
  * the buffer queue will have different length than before.
  */
-static ssize_t bufq_slurpn(struct bufq *q, size_t max_len,
-                           Curl_bufq_reader *reader, void *reader_ctx,
-                           CURLcode *err)
+static CURLcode bufq_slurpn(struct bufq *q, size_t max_len,
+                            Curl_bufq_reader *reader, void *reader_ctx,
+                            size_t *pnread)
 {
-  ssize_t nread = 0, n;
+  CURLcode result;
 
-  *err = CURLE_AGAIN;
+  *pnread = 0;
   while(1) {
-
-    n = Curl_bufq_sipn(q, max_len, reader, reader_ctx, err);
-    if(n < 0) {
-      if(!nread || *err != CURLE_AGAIN) {
+    size_t n;
+    result = Curl_bufq_sipn(q, max_len, reader, reader_ctx, &n);
+    if(result) {
+      if(!*pnread || result != CURLE_AGAIN) {
         /* blocked on first read or real error, fail */
-        nread = -1;
+        return result;
       }
-      else
-        *err = CURLE_OK;
+      result = CURLE_OK;
       break;
     }
     else if(n == 0) {
       /* eof */
-      *err = CURLE_OK;
+      result = CURLE_OK;
       break;
     }
-    nread += (size_t)n;
+    *pnread += n;
     if(max_len) {
-      DEBUGASSERT((size_t)n <= max_len);
-      max_len -= (size_t)n;
+      DEBUGASSERT(n <= max_len);
+      max_len -= n;
       if(!max_len)
         break;
     }
@@ -713,11 +605,11 @@
     if(q->tail && !chunk_is_full(q->tail))
       break;
   }
-  return nread;
+  return result;
 }
 
-ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
-                        void *reader_ctx, CURLcode *err)
+CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
+                         void *reader_ctx, size_t *pnread)
 {
-  return bufq_slurpn(q, 0, reader, reader_ctx, err);
+  return bufq_slurpn(q, 0, reader, reader_ctx, pnread);
 }
diff --git a/Utilities/cmcurl/lib/bufq.h b/Utilities/cmcurl/lib/bufq.h
index 60059de..7cd1826 100644
--- a/Utilities/cmcurl/lib/bufq.h
+++ b/Utilities/cmcurl/lib/bufq.h
@@ -163,31 +163,22 @@
 /**
  * Write buf to the end of the buffer queue. The buf is copied
  * and the amount of copied bytes is returned.
- * A return code of -1 indicates an error, setting `err` to the
- * cause. An err of CURLE_AGAIN is returned if the buffer queue is full.
+ * CURLE_AGAIN is returned if the buffer queue is full.
  */
-ssize_t Curl_bufq_write(struct bufq *q,
-                        const unsigned char *buf, size_t len,
-                        CURLcode *err);
-
-CURLcode Curl_bufq_cwrite(struct bufq *q,
-                         const char *buf, size_t len,
+CURLcode Curl_bufq_write(struct bufq *q,
+                         const unsigned char *buf, size_t len,
                          size_t *pnwritten);
 
-/**
- * Remove `len` bytes from the end of the buffer queue again.
- * Returns CURLE_AGAIN if less than `len` bytes were in the queue.
- */
-CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len);
+CURLcode Curl_bufq_cwrite(struct bufq *q,
+                          const char *buf, size_t len,
+                          size_t *pnwritten);
 
 /**
  * Read buf from the start of the buffer queue. The buf is copied
  * and the amount of copied bytes is returned.
- * A return code of -1 indicates an error, setting `err` to the
- * cause. An err of CURLE_AGAIN is returned if the buffer queue is empty.
  */
-ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
-                        CURLcode *err);
+CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
+                        size_t *pnread);
 
 CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
                          size_t *pnread);
@@ -214,9 +205,9 @@
  */
 void Curl_bufq_skip(struct bufq *q, size_t amount);
 
-typedef ssize_t Curl_bufq_writer(void *writer_ctx,
-                                 const unsigned char *buf, size_t len,
-                                 CURLcode *err);
+typedef CURLcode Curl_bufq_writer(void *writer_ctx,
+                                  const unsigned char *buf, size_t len,
+                                  size_t *pwritten);
 /**
  * Passes the chunks in the buffer queue to the writer and returns
  * the amount of buf written. A writer may return -1 and CURLE_AGAIN
@@ -226,24 +217,23 @@
  * Note that in case of a -1 chunks may have been written and
  * the buffer queue will have different length than before.
  */
-ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
-                       void *writer_ctx, CURLcode *err);
+CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
+                        void *writer_ctx, size_t *pwritten);
 
-typedef ssize_t Curl_bufq_reader(void *reader_ctx,
-                                 unsigned char *buf, size_t len,
-                                 CURLcode *err);
+typedef CURLcode Curl_bufq_reader(void *reader_ctx,
+                                  unsigned char *buf, size_t len,
+                                  size_t *pnread);
 
 /**
  * Read date and append it to the end of the buffer queue until the
  * reader returns blocking or the queue is full. A reader returns
- * -1 and CURLE_AGAIN to indicate blocking.
- * Returns the total amount of buf read (may be 0) or -1 on other
- * reader errors.
- * Note that in case of a -1 chunks may have been read and
+ * CURLE_AGAIN to indicate blocking.
+ * Returns the total amount of buf read (may be 0) in `pnread` on success.
+ * Note that in case of an error chunks may have been read and
  * the buffer queue will have different length than before.
  */
-ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
-                        void *reader_ctx, CURLcode *err);
+CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
+                         void *reader_ctx, size_t *pnread);
 
 /**
  * Read *once* up to `max_len` bytes and append it to the buffer.
@@ -251,9 +241,9 @@
  * Returns the total amount of buf read (may be 0) or -1 on other
  * reader errors.
  */
-ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
-                       Curl_bufq_reader *reader, void *reader_ctx,
-                       CURLcode *err);
+CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len,
+                        Curl_bufq_reader *reader, void *reader_ctx,
+                        size_t *pnread);
 
 /**
  * Write buf to the end of the buffer queue.
@@ -262,9 +252,9 @@
  * on or is placed into the buffer, depending on `len` and current
  * amount buffered, chunk size, etc.
  */
-ssize_t Curl_bufq_write_pass(struct bufq *q,
-                             const unsigned char *buf, size_t len,
-                             Curl_bufq_writer *writer, void *writer_ctx,
-                             CURLcode *err);
+CURLcode Curl_bufq_write_pass(struct bufq *q,
+                              const unsigned char *buf, size_t len,
+                              Curl_bufq_writer *writer, void *writer_ctx,
+                              size_t *pwritten);
 
 #endif /* HEADER_CURL_BUFQ_H */
diff --git a/Utilities/cmcurl/lib/cf-h1-proxy.c b/Utilities/cmcurl/lib/cf-h1-proxy.c
index df6f575..4aac877 100644
--- a/Utilities/cmcurl/lib/cf-h1-proxy.c
+++ b/Utilities/cmcurl/lib/cf-h1-proxy.c
@@ -252,7 +252,7 @@
   size_t request_len = curlx_dyn_len(&ts->request_data);
   size_t blen = request_len;
   CURLcode result = CURLE_OK;
-  ssize_t nwritten;
+  size_t nwritten;
 
   if(blen <= ts->nsent)
     goto out;  /* we are done */
@@ -260,16 +260,15 @@
   blen -= ts->nsent;
   buf += ts->nsent;
 
-  nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &result);
-  if(nwritten < 0) {
-    if(result == CURLE_AGAIN) {
+  result = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &nwritten);
+  if(result) {
+    if(result == CURLE_AGAIN)
       result = CURLE_OK;
-    }
     goto out;
   }
 
-  DEBUGASSERT(blen >= (size_t)nwritten);
-  ts->nsent += (size_t)nwritten;
+  DEBUGASSERT(blen >= nwritten);
+  ts->nsent += nwritten;
   Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten);
 
 out:
@@ -375,11 +374,8 @@
   error = SELECT_OK;
   *done = FALSE;
 
-  if(!Curl_conn_data_pending(data, cf->sockindex))
-    return CURLE_OK;
-
   while(ts->keepon) {
-    ssize_t nread;
+    size_t nread;
     char byte;
 
     /* Read one byte at a time to avoid a race condition. Wait at most one
@@ -397,7 +393,7 @@
       break;
     }
 
-    if(nread <= 0) {
+    if(!nread) {
       if(data->set.proxyauth && data->state.authproxy.avail &&
          data->state.aptr.proxyuserpwd) {
         /* proxy auth was requested and there was proxy auth available,
@@ -687,8 +683,8 @@
 }
 
 static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
-                                        struct Curl_easy *data,
-                                        struct easy_pollset *ps)
+                                       struct Curl_easy *data,
+                                       struct easy_pollset *ps)
 {
   struct h1_tunnel_state *ts = cf->ctx;
 
@@ -741,7 +737,6 @@
   cf_h1_proxy_connect,
   cf_h1_proxy_close,
   Curl_cf_def_shutdown,
-  Curl_cf_http_proxy_get_host,
   cf_h1_proxy_adjust_pollset,
   Curl_cf_def_data_pending,
   Curl_cf_def_send,
@@ -749,7 +744,7 @@
   Curl_cf_def_cntrl,
   Curl_cf_def_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
-  Curl_cf_def_query,
+  Curl_cf_http_proxy_query,
 };
 
 CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
diff --git a/Utilities/cmcurl/lib/cf-h2-proxy.c b/Utilities/cmcurl/lib/cf-h2-proxy.c
index d3bc4b0..8a853f6 100644
--- a/Utilities/cmcurl/lib/cf-h2-proxy.c
+++ b/Utilities/cmcurl/lib/cf-h2-proxy.c
@@ -28,6 +28,7 @@
 
 #include <nghttp2/nghttp2.h>
 #include "urldata.h"
+#include "url.h"
 #include "cfilters.h"
 #include "connect.h"
 #include "curl_trc.h"
@@ -80,7 +81,7 @@
 };
 
 static CURLcode tunnel_stream_init(struct Curl_cfilter *cf,
-                                    struct tunnel_stream *ts)
+                                   struct tunnel_stream *ts)
 {
   const char *hostname;
   int port;
@@ -218,58 +219,28 @@
                          struct tunnel_stream *tunnel)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  unsigned char bits;
-
   (void)cf;
-  bits = CURL_CSELECT_IN;
   if(!tunnel->closed && !tunnel->reset &&
      !Curl_bufq_is_empty(&ctx->tunnel.sendbuf))
-    bits |= CURL_CSELECT_OUT;
-  if(data->state.select_bits != bits) {
-    CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
-                tunnel->stream_id, bits);
-    data->state.select_bits = bits;
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
-  }
+    Curl_multi_mark_dirty(data);
 }
 
-static ssize_t proxy_nw_in_reader(void *reader_ctx,
-                                  unsigned char *buf, size_t buflen,
-                                  CURLcode *err)
-{
-  struct Curl_cfilter *cf = reader_ctx;
-  ssize_t nread;
-
-  if(cf) {
-    struct Curl_easy *data = CF_DATA_CURRENT(cf);
-    nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
-    CURL_TRC_CF(data, cf, "[0] nw_in_reader(len=%zu) -> %zd, %d",
-                buflen, nread, *err);
-  }
-  else {
-    nread = 0;
-  }
-  return nread;
-}
-
-static ssize_t proxy_h2_nw_out_writer(void *writer_ctx,
-                                      const unsigned char *buf, size_t buflen,
-                                      CURLcode *err)
+static CURLcode proxy_h2_nw_out_writer(void *writer_ctx,
+                                       const unsigned char *buf, size_t buflen,
+                                       size_t *pnwritten)
 {
   struct Curl_cfilter *cf = writer_ctx;
-  ssize_t nwritten;
-
+  *pnwritten = 0;
   if(cf) {
     struct Curl_easy *data = CF_DATA_CURRENT(cf);
-    nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
-                                 FALSE, err);
-    CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d",
-                buflen, nwritten, *err);
+    CURLcode result;
+    result = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
+                               FALSE, pnwritten);
+    CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %d, %zu",
+                buflen, result, *pnwritten);
+    return result;
   }
-  else {
-    nwritten = 0;
-  }
-  return nwritten;
+  return CURLE_FAILED_INIT;
 }
 
 static int proxy_h2_client_new(struct Curl_cfilter *cf,
@@ -297,8 +268,8 @@
 }
 
 static ssize_t on_session_send(nghttp2_session *h2,
-                              const uint8_t *buf, size_t blen,
-                              int flags, void *userp);
+                               const uint8_t *buf, size_t blen,
+                               int flags, void *userp);
 static int proxy_h2_on_frame_recv(nghttp2_session *session,
                                   const nghttp2_frame *frame,
                                   void *userp);
@@ -414,16 +385,16 @@
                                       struct Curl_easy *data)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
   (void)data;
   if(Curl_bufq_is_empty(&ctx->outbufq))
     return CURLE_OK;
 
-  nwritten = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf,
-                            &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf,
+                          &nwritten);
+  if(result) {
     if(result == CURLE_AGAIN) {
       CURL_TRC_CF(data, cf, "[0] flush nw send buffer(%zu) -> EAGAIN",
                   Curl_bufq_len(&ctx->outbufq));
@@ -479,7 +450,7 @@
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
-  ssize_t nread;
+  size_t nread;
 
   /* Process network input buffer fist */
   if(!Curl_bufq_is_empty(&ctx->inbufq)) {
@@ -496,10 +467,10 @@
         Curl_bufq_is_empty(&ctx->inbufq) && /* and we consumed our input */
         !Curl_bufq_is_full(&ctx->tunnel.recvbuf)) {
 
-    nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
-    CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %zd, %d",
-                Curl_bufq_len(&ctx->inbufq), nread, result);
-    if(nread < 0) {
+    result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
+    CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %d, %zu",
+                Curl_bufq_len(&ctx->inbufq), result, nread);
+    if(result) {
       if(result != CURLE_AGAIN) {
         failf(data, "Failed receiving HTTP2 data");
         return result;
@@ -547,17 +518,18 @@
   struct Curl_cfilter *cf = userp;
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result = CURLE_OK;
 
   (void)h2;
   (void)flags;
   DEBUGASSERT(data);
 
-  nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
-                                  proxy_h2_nw_out_writer, cf, &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
+                                proxy_h2_nw_out_writer, cf, &nwritten);
+  if(result) {
     if(result == CURLE_AGAIN) {
+      ctx->nw_out_blocked = 1;
       return NGHTTP2_ERR_WOULDBLOCK;
     }
     failf(data, "Failed sending HTTP2 data");
@@ -567,7 +539,8 @@
   if(!nwritten)
     return NGHTTP2_ERR_WOULDBLOCK;
 
-  return nwritten;
+  return (nwritten  > SSIZE_T_MAX) ?
+    NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten;
 }
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -817,7 +790,7 @@
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   struct tunnel_stream *ts;
   CURLcode result;
-  ssize_t nread;
+  size_t nread;
 
   (void)source;
   (void)data;
@@ -831,8 +804,8 @@
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   DEBUGASSERT(ts == &ctx->tunnel);
 
-  nread = Curl_bufq_read(&ts->sendbuf, buf, length, &result);
-  if(nread < 0) {
+  result = Curl_bufq_read(&ts->sendbuf, buf, length, &nread);
+  if(result) {
     if(result != CURLE_AGAIN)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     return NGHTTP2_ERR_DEFERRED;
@@ -842,7 +815,8 @@
 
   CURL_TRC_CF(data, cf, "[%d] tunnel_send_callback -> %zd",
               ts->stream_id, nread);
-  return nread;
+  return (nread  > SSIZE_T_MAX) ?
+    NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nread;
 }
 
 static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
@@ -851,7 +825,7 @@
 {
   struct Curl_cfilter *cf = userp;
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
   (void)flags;
@@ -861,14 +835,15 @@
   if(stream_id != ctx->tunnel.stream_id)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  nwritten = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &nwritten);
+  if(result) {
     if(result != CURLE_AGAIN)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
 #ifdef DEBUGBUILD
     nwritten = 0;
 #endif
   }
+  /* tunnel.recbuf has soft limit, any success MUST add all data */
   DEBUGASSERT((size_t)nwritten == len);
   return 0;
 }
@@ -1277,212 +1252,179 @@
   }
 }
 
-static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
-                                      struct Curl_easy *data,
-                                      CURLcode *err)
+static CURLcode h2_handle_tunnel_close(struct Curl_cfilter *cf,
+                                       struct Curl_easy *data,
+                                       size_t *pnread)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  ssize_t rv = 0;
 
+  *pnread = 0;
   if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
     CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
                 "connection", ctx->tunnel.stream_id);
     connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
-    *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
-    return -1;
+    return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
   }
   else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) {
     failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
           ctx->tunnel.stream_id, nghttp2_http2_strerror(ctx->tunnel.error),
           ctx->tunnel.error);
-    *err = CURLE_HTTP2_STREAM;
-    return -1;
+    return CURLE_HTTP2_STREAM;
   }
   else if(ctx->tunnel.reset) {
     failf(data, "HTTP/2 stream %u was reset", ctx->tunnel.stream_id);
-    *err = CURLE_RECV_ERROR;
-    return -1;
+    return CURLE_RECV_ERROR;
   }
 
-  *err = CURLE_OK;
-  rv = 0;
-  CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> %zd, %d",
-              ctx->tunnel.stream_id, rv, *err);
-  return rv;
+  CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> 0",
+              ctx->tunnel.stream_id);
+  return CURLE_OK;
 }
 
-static ssize_t tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                           char *buf, size_t len, CURLcode *err)
+static CURLcode tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                            char *buf, size_t len, size_t *pnread)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  ssize_t nread = -1;
+  CURLcode result = CURLE_AGAIN;
 
-  *err = CURLE_AGAIN;
-  if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) {
-    nread = Curl_bufq_read(&ctx->tunnel.recvbuf,
-                           (unsigned char *)buf, len, err);
-    if(nread < 0)
-      goto out;
-    DEBUGASSERT(nread > 0);
-  }
-
-  if(nread < 0) {
+  *pnread = 0;
+  if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf))
+    result = Curl_bufq_cread(&ctx->tunnel.recvbuf, buf, len, pnread);
+  else {
     if(ctx->tunnel.closed) {
-      nread = h2_handle_tunnel_close(cf, data, err);
+      result = h2_handle_tunnel_close(cf, data, pnread);
     }
     else if(ctx->tunnel.reset ||
             (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
             (ctx->rcvd_goaway &&
              ctx->last_stream_id < ctx->tunnel.stream_id)) {
-      *err = CURLE_RECV_ERROR;
-      nread = -1;
+      result = CURLE_RECV_ERROR;
     }
-  }
-  else if(nread == 0) {
-    *err = CURLE_AGAIN;
-    nread = -1;
+    else
+      result = CURLE_AGAIN;
   }
 
-out:
-  CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %zd, %d",
-              ctx->tunnel.stream_id, len, nread, *err);
-  return nread;
+  CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %d, %zu",
+              ctx->tunnel.stream_id, len, result, *pnread);
+  return result;
 }
 
-static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
-                                struct Curl_easy *data,
-                                char *buf, size_t len, CURLcode *err)
+static CURLcode cf_h2_proxy_recv(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 char *buf, size_t len,
+                                 size_t *pnread)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  ssize_t nread = -1;
   struct cf_call_data save;
   CURLcode result;
 
-  if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
-    *err = CURLE_RECV_ERROR;
-    return -1;
-  }
+  *pnread = 0;
   CF_DATA_SAVE(save, cf, data);
 
+  if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
+    result = CURLE_RECV_ERROR;
+    goto out;
+  }
+
   if(Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) {
-    *err = proxy_h2_progress_ingress(cf, data);
-    if(*err)
+    result = proxy_h2_progress_ingress(cf, data);
+    if(result)
       goto out;
   }
 
-  nread = tunnel_recv(cf, data, buf, len, err);
+  result = tunnel_recv(cf, data, buf, len, pnread);
 
-  if(nread > 0) {
-    CURL_TRC_CF(data, cf, "[%d] increase window by %zd",
-                ctx->tunnel.stream_id, nread);
-    nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread);
+  if(!result) {
+    CURL_TRC_CF(data, cf, "[%d] increase window by %zu",
+                ctx->tunnel.stream_id, *pnread);
+    nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, *pnread);
   }
 
-  result = proxy_h2_progress_egress(cf, data);
-  if(result && (result != CURLE_AGAIN)) {
-    *err = result;
-    nread = -1;
-  }
+  result = Curl_1st_fatal(result, proxy_h2_progress_egress(cf, data));
 
 out:
   if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
-     (nread >= 0 || *err == CURLE_AGAIN)) {
+     (!result || (result == CURLE_AGAIN))) {
     /* data pending and no fatal error to report. Need to trigger
      * draining to avoid stalling when no socket events happen. */
     drain_tunnel(cf, data, &ctx->tunnel);
   }
-  CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d",
-              ctx->tunnel.stream_id, len, nread, *err);
+  CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu",
+              ctx->tunnel.stream_id, len, result, *pnread);
   CF_DATA_RESTORE(cf, save);
-  return nread;
+  return result;
 }
 
-static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
-                                struct Curl_easy *data,
-                                const void *buf, size_t len, bool eos,
-                                CURLcode *err)
+static CURLcode cf_h2_proxy_send(struct Curl_cfilter *cf,
+                                 struct Curl_easy *data,
+                                 const void *buf, size_t len, bool eos,
+                                 size_t *pnwritten)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   struct cf_call_data save;
   int rv;
-  ssize_t nwritten;
   CURLcode result;
 
   (void)eos;
-  if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
-    *err = CURLE_SEND_ERROR;
-    return -1;
-  }
+  *pnwritten = 0;
   CF_DATA_SAVE(save, cf, data);
 
-  if(ctx->tunnel.closed) {
-    nwritten = -1;
-    *err = CURLE_SEND_ERROR;
+  if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
+    result = CURLE_SEND_ERROR;
     goto out;
   }
-  else {
-    nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err);
-    if(nwritten < 0 && (*err != CURLE_AGAIN))
-      goto out;
+
+  if(ctx->tunnel.closed) {
+    result = CURLE_SEND_ERROR;
+    goto out;
   }
 
+  result = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, pnwritten);
+  CURL_TRC_CF(data, cf, "cf_send(), bufq_write %d, %zd", result, *pnwritten);
+  if(result && (result != CURLE_AGAIN))
+    goto out;
+
   if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
     /* req body data is buffered, resume the potentially suspended stream */
     rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id);
     if(nghttp2_is_fatal(rv)) {
-      *err = CURLE_SEND_ERROR;
-      nwritten = -1;
+      result = CURLE_SEND_ERROR;
       goto out;
     }
   }
 
-  result = proxy_h2_progress_ingress(cf, data);
-  if(result) {
-    *err = result;
-    nwritten = -1;
-    goto out;
-  }
+  result = Curl_1st_fatal(result, proxy_h2_progress_ingress(cf, data));
+  result = Curl_1st_fatal(result, proxy_h2_progress_egress(cf, data));
 
-  /* Call the nghttp2 send loop and flush to write ALL buffered data,
-   * headers and/or request body completely out to the network */
-  result = proxy_h2_progress_egress(cf, data);
-  if(result && (result != CURLE_AGAIN)) {
-    *err = result;
-    nwritten = -1;
-    goto out;
-  }
-
-  if(proxy_h2_should_close_session(ctx)) {
+  if(!result && proxy_h2_should_close_session(ctx)) {
     /* nghttp2 thinks this session is done. If the stream has not been
      * closed, this is an error state for out transfer */
     if(ctx->tunnel.closed) {
-      *err = CURLE_SEND_ERROR;
-      nwritten = -1;
+      result = CURLE_SEND_ERROR;
     }
     else {
       CURL_TRC_CF(data, cf, "[0] send: nothing to do in this session");
-      *err = CURLE_HTTP2;
-      nwritten = -1;
+      result = CURLE_HTTP2;
     }
   }
 
 out:
   if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
-     (nwritten >= 0 || *err == CURLE_AGAIN)) {
+     (!result || (result == CURLE_AGAIN))) {
     /* data pending and no fatal error to report. Need to trigger
      * draining to avoid stalling when no socket events happen. */
     drain_tunnel(cf, data, &ctx->tunnel);
   }
-  CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, "
+  CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, "
               "h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)",
-              ctx->tunnel.stream_id, len, nwritten, *err,
+              ctx->tunnel.stream_id, len, result, *pnwritten,
               nghttp2_session_get_stream_remote_window_size(
                   ctx->h2, ctx->tunnel.stream_id),
               nghttp2_session_get_remote_window_size(ctx->h2),
               Curl_bufq_len(&ctx->tunnel.sendbuf),
               Curl_bufq_len(&ctx->outbufq));
   CF_DATA_RESTORE(cf, save);
-  return nwritten;
+  return result;
 }
 
 static CURLcode cf_h2_proxy_flush(struct Curl_cfilter *cf,
@@ -1533,11 +1475,11 @@
        not in use by any other transfer, there should not be any data here,
        only "protocol frames" */
     CURLcode result;
-    ssize_t nread = -1;
+    size_t nread;
 
     *input_pending = FALSE;
-    nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
-    if(nread != -1) {
+    result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
+    if(!result) {
       if(proxy_h2_process_pending_input(cf, data, &result) < 0)
         /* immediate error, considered dead */
         alive = FALSE;
@@ -1559,15 +1501,16 @@
                                  bool *input_pending)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  CURLcode result;
+  bool alive;
   struct cf_call_data save;
 
+  *input_pending = FALSE;
   CF_DATA_SAVE(save, cf, data);
-  result = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending));
+  alive = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending));
   CURL_TRC_CF(data, cf, "[0] conn alive -> %d, input_pending=%d",
-              result, *input_pending);
+              alive, *input_pending);
   CF_DATA_RESTORE(cf, save);
-  return result;
+  return alive;
 }
 
 static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf,
@@ -1577,6 +1520,10 @@
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
 
   switch(query) {
+  case CF_QUERY_HOST_PORT:
+    *pres1 = (int)cf->conn->http_proxy.port;
+    *((const char **)pres2) = cf->conn->http_proxy.host.name;
+    return CURLE_OK;
   case CF_QUERY_NEED_FLUSH: {
     if(!Curl_bufq_is_empty(&ctx->outbufq) ||
        !Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
@@ -1624,7 +1571,6 @@
   cf_h2_proxy_connect,
   cf_h2_proxy_close,
   cf_h2_proxy_shutdown,
-  Curl_cf_http_proxy_get_host,
   cf_h2_proxy_adjust_pollset,
   cf_h2_proxy_data_pending,
   cf_h2_proxy_send,
diff --git a/Utilities/cmcurl/lib/cf-haproxy.c b/Utilities/cmcurl/lib/cf-haproxy.c
index 7bc12db..6183ca2 100644
--- a/Utilities/cmcurl/lib/cf-haproxy.c
+++ b/Utilities/cmcurl/lib/cf-haproxy.c
@@ -131,17 +131,17 @@
   case HAPROXY_SEND:
     len = curlx_dyn_len(&ctx->data_out);
     if(len > 0) {
-      ssize_t nwritten;
-      nwritten = Curl_conn_cf_send(cf->next, data,
-                                   curlx_dyn_ptr(&ctx->data_out), len, FALSE,
-                                   &result);
-      if(nwritten < 0) {
+      size_t nwritten;
+      result = Curl_conn_cf_send(cf->next, data,
+                                 curlx_dyn_ptr(&ctx->data_out), len, FALSE,
+                                 &nwritten);
+      if(result) {
         if(result != CURLE_AGAIN)
           goto out;
         result = CURLE_OK;
         nwritten = 0;
       }
-      curlx_dyn_tail(&ctx->data_out, len - (size_t)nwritten);
+      curlx_dyn_tail(&ctx->data_out, len - nwritten);
       if(curlx_dyn_len(&ctx->data_out) > 0) {
         result = CURLE_OK;
         goto out;
@@ -197,7 +197,6 @@
   cf_haproxy_connect,
   cf_haproxy_close,
   Curl_cf_def_shutdown,
-  Curl_cf_def_get_host,
   cf_haproxy_adjust_pollset,
   Curl_cf_def_data_pending,
   Curl_cf_def_send,
diff --git a/Utilities/cmcurl/lib/cf-https-connect.c b/Utilities/cmcurl/lib/cf-https-connect.c
index cd0d226..b89ed80 100644
--- a/Utilities/cmcurl/lib/cf-https-connect.c
+++ b/Utilities/cmcurl/lib/cf-https-connect.c
@@ -55,6 +55,7 @@
   CURLcode result;
   struct curltime started;
   int reply_ms;
+  unsigned char transport;
   enum alpnid alpn_id;
   BIT(shutdown);
 };
@@ -117,17 +118,20 @@
   CURLcode result;          /* overall result */
   struct cf_hc_baller ballers[2];
   size_t baller_count;
-  unsigned int soft_eyeballs_timeout_ms;
-  unsigned int hard_eyeballs_timeout_ms;
+  timediff_t soft_eyeballs_timeout_ms;
+  timediff_t hard_eyeballs_timeout_ms;
 };
 
 static void cf_hc_baller_assign(struct cf_hc_baller *b,
-                                enum alpnid alpn_id)
+                                enum alpnid alpn_id,
+                                unsigned char def_transport)
 {
   b->alpn_id = alpn_id;
+  b->transport = def_transport;
   switch(b->alpn_id) {
   case ALPN_h3:
     b->name = "h3";
+    b->transport = TRNSPRT_QUIC;
     break;
   case ALPN_h2:
     b->name = "h2";
@@ -218,6 +222,7 @@
                 winner->name, (int)curlx_timediff(curlx_now(),
                                                   winner->started));
 
+  /* install the winning filter below this one. */
   cf->next = winner->cf;
   winner->cf = NULL;
 
@@ -268,15 +273,16 @@
   }
   elapsed_ms = curlx_timediff(now, ctx->started);
   if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
-    CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting %s",
+    CURL_TRC_CF(data, cf, "hard timeout of %" FMT_TIMEDIFF_T "ms reached, "
+                "starting %s",
                 ctx->hard_eyeballs_timeout_ms, ctx->ballers[idx].name);
     return TRUE;
   }
 
   if((idx > 0) && (elapsed_ms >= ctx->soft_eyeballs_timeout_ms)) {
     if(cf_hc_baller_reply_ms(&ctx->ballers[idx - 1], data) < 0) {
-      CURL_TRC_CF(data, cf, "soft timeout of %dms reached, %s has not "
-                  "seen any data, starting %s",
+      CURL_TRC_CF(data, cf, "soft timeout of %" FMT_TIMEDIFF_T "ms reached, "
+                  "%s has not seen any data, starting %s",
                   ctx->soft_eyeballs_timeout_ms,
                   ctx->ballers[idx - 1].name, ctx->ballers[idx].name);
       return TRUE;
@@ -311,11 +317,11 @@
       DEBUGASSERT(!ctx->ballers[i].cf);
     CURL_TRC_CF(data, cf, "connect, init");
     ctx->started = now;
-    cf_hc_baller_init(&ctx->ballers[0], cf, data, cf->conn->transport);
+    cf_hc_baller_init(&ctx->ballers[0], cf, data, ctx->ballers[0].transport);
     if(ctx->baller_count > 1) {
       Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
-      CURL_TRC_CF(data, cf, "set next attempt to start in %ums",
-                  ctx->soft_eyeballs_timeout_ms);
+      CURL_TRC_CF(data, cf, "set next attempt to start in %" FMT_TIMEDIFF_T
+                  "ms", ctx->soft_eyeballs_timeout_ms);
     }
     ctx->state = CF_HC_CONNECT;
     FALLTHROUGH();
@@ -330,7 +336,7 @@
     }
 
     if(time_to_start_next(cf, data, 1, now)) {
-      cf_hc_baller_init(&ctx->ballers[1], cf, data, cf->conn->transport);
+      cf_hc_baller_init(&ctx->ballers[1], cf, data, ctx->ballers[1].transport);
     }
 
     if((ctx->baller_count > 1) && cf_hc_baller_is_active(&ctx->ballers[1])) {
@@ -423,8 +429,8 @@
 }
 
 static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  struct easy_pollset *ps)
+                                 struct Curl_easy *data,
+                                 struct easy_pollset *ps)
 {
   if(!cf->connected) {
     struct cf_hc_ctx *ctx = cf->ctx;
@@ -561,7 +567,6 @@
   cf_hc_connect,
   cf_hc_close,
   cf_hc_shutdown,
-  Curl_cf_def_get_host,
   cf_hc_adjust_pollset,
   cf_hc_data_pending,
   Curl_cf_def_send,
@@ -574,7 +579,8 @@
 
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
                              struct Curl_easy *data,
-                             enum alpnid *alpnids, size_t alpn_count)
+                             enum alpnid *alpnids, size_t alpn_count,
+                             unsigned char def_transport)
 {
   struct Curl_cfilter *cf = NULL;
   struct cf_hc_ctx *ctx;
@@ -596,7 +602,7 @@
     goto out;
   }
   for(i = 0; i < alpn_count; ++i)
-    cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]);
+    cf_hc_baller_assign(&ctx->ballers[i], alpnids[i], def_transport);
   for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
     ctx->ballers[i].alpn_id = ALPN_none;
   ctx->baller_count = alpn_count;
@@ -616,13 +622,14 @@
 static CURLcode cf_http_connect_add(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     int sockindex,
-                                    enum alpnid *alpn_ids, size_t alpn_count)
+                                    enum alpnid *alpn_ids, size_t alpn_count,
+                                    unsigned char def_transport)
 {
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  result = cf_hc_create(&cf, data, alpn_ids, alpn_count);
+  result = cf_hc_create(&cf, data, alpn_ids, alpn_count, def_transport);
   if(result)
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -679,7 +686,7 @@
           continue;
         switch(alpn) {
         case ALPN_h3:
-          if(Curl_conn_may_http3(data, conn))
+          if(Curl_conn_may_http3(data, conn, conn->transport_wanted))
             break;  /* not possible */
           if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
             CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
@@ -708,7 +715,7 @@
     if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
        (data->state.http_neg.wanted & CURL_HTTP_V3x) &&
        !cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) {
-      result = Curl_conn_may_http3(data, conn);
+      result = Curl_conn_may_http3(data, conn, conn->transport_wanted);
       if(!result) {
         CURL_TRC_CF(data, cf, "adding wanted h3");
         alpn_ids[alpn_count++] = ALPN_h3;
@@ -733,7 +740,9 @@
   /* If we identified ALPNs to use, install our filter. Otherwise,
    * install nothing, so our call will use a default connect setup. */
   if(alpn_count) {
-    result = cf_http_connect_add(data, conn, sockindex, alpn_ids, alpn_count);
+    result = cf_http_connect_add(data, conn, sockindex,
+                                 alpn_ids, alpn_count,
+                                 conn->transport_wanted);
   }
 
 out:
diff --git a/Utilities/cmcurl/lib/cf-socket.c b/Utilities/cmcurl/lib/cf-socket.c
index e319772..273258f 100644
--- a/Utilities/cmcurl/lib/cf-socket.c
+++ b/Utilities/cmcurl/lib/cf-socket.c
@@ -73,7 +73,6 @@
 #include "url.h" /* for Curl_safefree() */
 #include "multiif.h"
 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "inet_ntop.h"
 #include "curlx/inet_pton.h"
 #include "progress.h"
 #include "curlx/warnless.h"
@@ -395,10 +394,10 @@
  *
  */
 CURLcode Curl_socket_open(struct Curl_easy *data,
-                            const struct Curl_addrinfo *ai,
-                            struct Curl_sockaddr_ex *addr,
-                            int transport,
-                            curl_socket_t *sockfd)
+                          const struct Curl_addrinfo *ai,
+                          struct Curl_sockaddr_ex *addr,
+                          int transport,
+                          curl_socket_t *sockfd)
 {
   struct Curl_sockaddr_ex dummy;
   CURLcode result;
@@ -996,8 +995,6 @@
       cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
     socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
     ctx->sock = CURL_SOCKET_BAD;
-    if(ctx->active && cf->sockindex == FIRSTSOCKET)
-      cf->conn->remote_addr = NULL;
     ctx->active = FALSE;
     memset(&ctx->started_at, 0, sizeof(ctx->started_at));
     memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
@@ -1095,7 +1092,7 @@
 }
 
 static CURLcode cf_socket_open(struct Curl_cfilter *cf,
-                              struct Curl_easy *data)
+                               struct Curl_easy *data)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
   int error = 0;
@@ -1378,22 +1375,9 @@
   return result;
 }
 
-static void cf_socket_get_host(struct Curl_cfilter *cf,
-                               struct Curl_easy *data,
-                               const char **phost,
-                               const char **pdisplay_host,
-                               int *pport)
-{
-  struct cf_socket_ctx *ctx = cf->ctx;
-  (void)data;
-  *phost = cf->conn->host.name;
-  *pdisplay_host = cf->conn->host.dispname;
-  *pport = ctx->ip.remote_port;
-}
-
 static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
-                                      struct Curl_easy *data,
-                                      struct easy_pollset *ps)
+                                     struct Curl_easy *data,
+                                     struct easy_pollset *ps)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
 
@@ -1420,17 +1404,6 @@
   }
 }
 
-static bool cf_socket_data_pending(struct Curl_cfilter *cf,
-                                   const struct Curl_easy *data)
-{
-  struct cf_socket_ctx *ctx = cf->ctx;
-  int readable;
-
-  (void)data;
-  readable = SOCKET_READABLE(ctx->sock, 0);
-  return readable > 0 && (readable & CURL_CSELECT_IN);
-}
-
 #ifdef USE_WINSOCK
 
 #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
@@ -1457,17 +1430,18 @@
 
 #endif /* USE_WINSOCK */
 
-static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              const void *buf, size_t len, bool eos,
-                              CURLcode *err)
+static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                               const void *buf, size_t len, bool eos,
+                               size_t *pnwritten)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
   curl_socket_t fdsave;
   ssize_t nwritten;
   size_t orig_len = len;
+  CURLcode result = CURLE_OK;
 
   (void)eos; /* unused */
-  *err = CURLE_OK;
+  *pnwritten = 0;
   fdsave = cf->conn->sock[cf->sockindex];
   cf->conn->sock[cf->sockindex] = ctx->sock;
 
@@ -1478,10 +1452,8 @@
     Curl_rand_bytes(data, FALSE, &c, 1);
     if(c >= ((100-ctx->wblock_percent)*256/100)) {
       CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
-      *err = CURLE_AGAIN;
-      nwritten = -1;
       cf->conn->sock[cf->sockindex] = fdsave;
-      return nwritten;
+      return CURLE_AGAIN;
     }
   }
   if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
@@ -1496,15 +1468,14 @@
 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
   if(cf->conn->bits.tcp_fastopen) {
     nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
-                      &cf->conn->remote_addr->curl_sa_addr,
-                      cf->conn->remote_addr->addrlen);
+                      &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
     cf->conn->bits.tcp_fastopen = FALSE;
   }
   else
 #endif
     nwritten = swrite(ctx->sock, buf, len);
 
-  if(-1 == nwritten) {
+  if(nwritten < 0) {
     int sockerr = SOCKERRNO;
 
     if(
@@ -1521,36 +1492,38 @@
 #endif
       ) {
       /* this is just a case of EWOULDBLOCK */
-      *err = CURLE_AGAIN;
+      result = CURLE_AGAIN;
     }
     else {
       char buffer[STRERROR_LEN];
       failf(data, "Send failure: %s",
             Curl_strerror(sockerr, buffer, sizeof(buffer)));
       data->state.os_errno = sockerr;
-      *err = CURLE_SEND_ERROR;
+      result = CURLE_SEND_ERROR;
     }
   }
+  else
+    *pnwritten = (size_t)nwritten;
 
 #if defined(USE_WINSOCK)
-  if(!*err)
+  if(!result)
     win_update_sndbuf_size(ctx);
 #endif
 
-  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
-              orig_len, (int)nwritten, *err);
+  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, %zu",
+              orig_len, result, *pnwritten);
   cf->conn->sock[cf->sockindex] = fdsave;
-  return nwritten;
+  return result;
 }
 
-static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              char *buf, size_t len, CURLcode *err)
+static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                               char *buf, size_t len, size_t *pnread)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
+  CURLcode result = CURLE_OK;
   ssize_t nread;
 
-  *err = CURLE_OK;
-
+  *pnread = 0;
 #ifdef DEBUGBUILD
   /* simulate network blocking/partial reads */
   if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
@@ -1558,8 +1531,7 @@
     Curl_rand(data, &c, 1);
     if(c >= ((100-ctx->rblock_percent)*256/100)) {
       CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
-      *err = CURLE_AGAIN;
-      return -1;
+      return CURLE_AGAIN;
     }
   }
   if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
@@ -1570,10 +1542,9 @@
   }
 #endif
 
-  *err = CURLE_OK;
   nread = sread(ctx->sock, buf, len);
 
-  if(-1 == nread) {
+  if(nread < 0) {
     int sockerr = SOCKERRNO;
 
     if(
@@ -1589,25 +1560,25 @@
 #endif
       ) {
       /* this is just a case of EWOULDBLOCK */
-      *err = CURLE_AGAIN;
+      result = CURLE_AGAIN;
     }
     else {
       char buffer[STRERROR_LEN];
-
       failf(data, "Recv failure: %s",
             Curl_strerror(sockerr, buffer, sizeof(buffer)));
       data->state.os_errno = sockerr;
-      *err = CURLE_RECV_ERROR;
+      result = CURLE_RECV_ERROR;
     }
   }
+  else
+    *pnread = (size_t)nread;
 
-  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
-              *err);
-  if(nread > 0 && !ctx->got_first_byte) {
+  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread);
+  if(!result && !ctx->got_first_byte) {
     ctx->first_byte_at = curlx_now();
     ctx->got_first_byte = TRUE;
   }
-  return nread;
+  return result;
 }
 
 static void cf_socket_update_data(struct Curl_cfilter *cf,
@@ -1631,7 +1602,6 @@
   set_local_ip(cf, data);
   if(cf->sockindex == FIRSTSOCKET) {
     cf->conn->primary = ctx->ip;
-    cf->conn->remote_addr = &ctx->addr;
   #ifdef USE_IPV6
     cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6);
   #endif
@@ -1713,6 +1683,15 @@
     DEBUGASSERT(pres2);
     *((curl_socket_t *)pres2) = ctx->sock;
     return CURLE_OK;
+  case CF_QUERY_TRANSPORT:
+    DEBUGASSERT(pres1);
+    *pres1 = ctx->transport;
+    return CURLE_OK;
+  case CF_QUERY_REMOTE_ADDR:
+    DEBUGASSERT(pres2);
+    *((const struct Curl_sockaddr_ex **)pres2) = cf->connected ?
+                                                 &ctx->addr : NULL;
+    return CURLE_OK;
   case CF_QUERY_CONNECT_REPLY_MS:
     if(ctx->got_first_byte) {
       timediff_t ms = curlx_timediff(ctx->first_byte_at, ctx->started_at);
@@ -1763,9 +1742,8 @@
   cf_tcp_connect,
   cf_socket_close,
   cf_socket_shutdown,
-  cf_socket_get_host,
   cf_socket_adjust_pollset,
-  cf_socket_data_pending,
+  Curl_cf_def_data_pending,
   cf_socket_send,
   cf_socket_recv,
   cf_socket_cntrl,
@@ -1918,9 +1896,8 @@
   cf_udp_connect,
   cf_socket_close,
   cf_socket_shutdown,
-  cf_socket_get_host,
   cf_socket_adjust_pollset,
-  cf_socket_data_pending,
+  Curl_cf_def_data_pending,
   cf_socket_send,
   cf_socket_recv,
   cf_socket_cntrl,
@@ -1973,9 +1950,8 @@
   cf_tcp_connect,
   cf_socket_close,
   cf_socket_shutdown,
-  cf_socket_get_host,
   cf_socket_adjust_pollset,
-  cf_socket_data_pending,
+  Curl_cf_def_data_pending,
   cf_socket_send,
   cf_socket_recv,
   cf_socket_cntrl,
@@ -2020,7 +1996,7 @@
 }
 
 static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
-                                          struct Curl_easy *data)
+                                         struct Curl_easy *data)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
   timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
@@ -2194,9 +2170,8 @@
   cf_tcp_accept_connect,
   cf_socket_close,
   cf_socket_shutdown,
-  cf_socket_get_host,
   cf_socket_adjust_pollset,
-  cf_socket_data_pending,
+  Curl_cf_def_data_pending,
   cf_socket_send,
   cf_socket_recv,
   cf_socket_cntrl,
@@ -2222,7 +2197,7 @@
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
-  ctx->transport = conn->transport;
+  ctx->transport = TRNSPRT_TCP;
   ctx->sock = *s;
   ctx->listening = TRUE;
   ctx->accepted = FALSE;
diff --git a/Utilities/cmcurl/lib/cf-socket.h b/Utilities/cmcurl/lib/cf-socket.h
index d3e3509..90daf07 100644
--- a/Utilities/cmcurl/lib/cf-socket.h
+++ b/Utilities/cmcurl/lib/cf-socket.h
@@ -68,10 +68,10 @@
  *
  */
 CURLcode Curl_socket_open(struct Curl_easy *data,
-                            const struct Curl_addrinfo *ai,
-                            struct Curl_sockaddr_ex *addr,
-                            int transport,
-                            curl_socket_t *sockfd);
+                          const struct Curl_addrinfo *ai,
+                          struct Curl_sockaddr_ex *addr,
+                          int transport,
+                          curl_socket_t *sockfd);
 
 int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
                       curl_socket_t sock);
diff --git a/Utilities/cmcurl/lib/cfilters.c b/Utilities/cmcurl/lib/cfilters.c
index 00090f0..01f1e28 100644
--- a/Utilities/cmcurl/lib/cfilters.c
+++ b/Utilities/cmcurl/lib/cfilters.c
@@ -67,22 +67,9 @@
 static void conn_report_connect_stats(struct Curl_easy *data,
                                       struct connectdata *conn);
 
-void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          const char **phost, const char **pdisplay_host,
-                          int *pport)
-{
-  if(cf->next)
-    cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
-  else {
-    *phost = cf->conn->host.name;
-    *pdisplay_host = cf->conn->host.dispname;
-    *pport = cf->conn->primary.remote_port;
-  }
-}
-
 void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
-                                 struct Curl_easy *data,
-                                 struct easy_pollset *ps)
+                                struct Curl_easy *data,
+                                struct easy_pollset *ps)
 {
   /* NOP */
   (void)cf;
@@ -97,21 +84,23 @@
     cf->next->cft->has_data_pending(cf->next, data) : FALSE;
 }
 
-ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
                           const void *buf, size_t len, bool eos,
-                          CURLcode *err)
+                          size_t *pnwritten)
 {
-  return cf->next ?
-    cf->next->cft->do_send(cf->next, data, buf, len, eos, err) :
-    CURLE_RECV_ERROR;
+  if(cf->next)
+    return cf->next->cft->do_send(cf->next, data, buf, len, eos, pnwritten);
+  *pnwritten = 0;
+  return CURLE_RECV_ERROR;
 }
 
-ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          char *buf, size_t len, CURLcode *err)
+CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          char *buf, size_t len, size_t *pnread)
 {
-  return cf->next ?
-    cf->next->cft->do_recv(cf->next, data, buf, len, err) :
-    CURLE_SEND_ERROR;
+  if(cf->next)
+    return cf->next->cft->do_recv(cf->next, data, buf, len, pnread);
+  *pnread = 0;
+  return CURLE_SEND_ERROR;
 }
 
 bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
@@ -234,52 +223,102 @@
   return result;
 }
 
-ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
-                     size_t len, CURLcode *code)
+CURLcode Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
+                      size_t len, size_t *pnread)
 {
   struct Curl_cfilter *cf;
 
   DEBUGASSERT(data);
   DEBUGASSERT(data->conn);
-  *code = CURLE_OK;
   cf = data->conn->cfilter[num];
-  while(cf && !cf->connected) {
+  while(cf && !cf->connected)
     cf = cf->next;
-  }
-  if(cf) {
-    ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code);
-    DEBUGASSERT(nread >= 0 || *code);
-    DEBUGASSERT(nread < 0 || !*code);
-    return nread;
-  }
+  if(cf)
+    return cf->cft->do_recv(cf, data, buf, len, pnread);
   failf(data, "recv: no filter connected");
-  *code = CURLE_FAILED_INIT;
-  return -1;
+  DEBUGASSERT(0);
+  *pnread = 0;
+  return CURLE_FAILED_INIT;
 }
 
-ssize_t Curl_cf_send(struct Curl_easy *data, int num,
-                     const void *mem, size_t len, bool eos,
-                     CURLcode *code)
+CURLcode Curl_cf_send(struct Curl_easy *data, int num,
+                      const void *mem, size_t len, bool eos,
+                      size_t *pnwritten)
 {
   struct Curl_cfilter *cf;
 
   DEBUGASSERT(data);
   DEBUGASSERT(data->conn);
-  *code = CURLE_OK;
   cf = data->conn->cfilter[num];
-  while(cf && !cf->connected) {
+  while(cf && !cf->connected)
     cf = cf->next;
-  }
   if(cf) {
-    ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, eos, code);
-    DEBUGASSERT(nwritten >= 0 || *code);
-    DEBUGASSERT(nwritten < 0 || !*code || !len);
-    return nwritten;
+    return cf->cft->do_send(cf, data, mem, len, eos, pnwritten);
   }
   failf(data, "send: no filter connected");
   DEBUGASSERT(0);
-  *code = CURLE_FAILED_INIT;
-  return -1;
+  *pnwritten = 0;
+  return CURLE_FAILED_INIT;
+}
+
+struct cf_io_ctx {
+  struct Curl_easy *data;
+  struct Curl_cfilter *cf;
+};
+
+static CURLcode cf_bufq_reader(void *writer_ctx,
+                               unsigned char *buf, size_t blen,
+                               size_t *pnread)
+{
+  struct cf_io_ctx *io = writer_ctx;
+  return Curl_conn_cf_recv(io->cf, io->data, (char *)buf, blen, pnread);
+}
+
+CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct bufq *bufq,
+                           size_t maxlen,
+                           size_t *pnread)
+{
+  struct cf_io_ctx io;
+
+  if(!cf || !data) {
+    *pnread = 0;
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  io.data = data;
+  io.cf = cf;
+  return Curl_bufq_sipn(bufq, maxlen, cf_bufq_reader, &io, pnread);
+}
+
+static CURLcode cf_bufq_writer(void *writer_ctx,
+                               const unsigned char *buf, size_t buflen,
+                               size_t *pnwritten)
+{
+  struct cf_io_ctx *io = writer_ctx;
+  return Curl_conn_cf_send(io->cf, io->data, (const char *)buf,
+                           buflen, FALSE, pnwritten);
+}
+
+CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct bufq *bufq,
+                           const unsigned char *buf, size_t blen,
+                           size_t *pnwritten)
+{
+  struct cf_io_ctx io;
+
+  if(!cf || !data) {
+    *pnwritten = 0;
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  io.data = data;
+  io.cf = cf;
+  if(buf && blen)
+    return Curl_bufq_write_pass(bufq, buf, blen, cf_bufq_writer, &io,
+                                pnwritten);
+  else
+    return Curl_bufq_pass(bufq, cf_bufq_writer, &io, pnwritten);
 }
 
 CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
@@ -381,23 +420,23 @@
     cf->cft->do_close(cf, data);
 }
 
-ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          const void *buf, size_t len, bool eos,
-                          CURLcode *err)
+CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           const void *buf, size_t len, bool eos,
+                           size_t *pnwritten)
 {
   if(cf)
-    return cf->cft->do_send(cf, data, buf, len, eos, err);
-  *err = CURLE_SEND_ERROR;
-  return -1;
+    return cf->cft->do_send(cf, data, buf, len, eos, pnwritten);
+  *pnwritten = 0;
+  return CURLE_SEND_ERROR;
 }
 
-ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          char *buf, size_t len, CURLcode *err)
+CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           char *buf, size_t len, size_t *pnread)
 {
   if(cf)
-    return cf->cft->do_recv(cf, data, buf, len, err);
-  *err = CURLE_RECV_ERROR;
-  return -1;
+    return cf->cft->do_recv(cf, data, buf, len, pnread);
+  *pnread = 0;
+  return CURLE_RECV_ERROR;
 }
 
 CURLcode Curl_conn_connect(struct Curl_easy *data,
@@ -541,6 +580,19 @@
   return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
 }
 
+bool Curl_conn_get_ssl_info(struct Curl_easy *data,
+                            struct connectdata *conn, int sockindex,
+                            struct curl_tlssessioninfo *info)
+{
+  if(Curl_conn_is_ssl(conn, sockindex)) {
+    struct Curl_cfilter *cf = conn->cfilter[sockindex];
+    CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO,
+                               NULL, (void *)info) : CURLE_UNKNOWN_OPTION;
+    return !result;
+  }
+  return FALSE;
+}
+
 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
 {
   struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
@@ -554,6 +606,13 @@
   return FALSE;
 }
 
+unsigned char Curl_conn_get_transport(struct Curl_easy *data,
+                                      struct connectdata *conn)
+{
+  struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
+  return Curl_conn_cf_get_transport(cf, data);
+}
+
 unsigned char Curl_conn_http_version(struct Curl_easy *data,
                                      struct connectdata *conn)
 {
@@ -678,31 +737,35 @@
   return Curl_poll(pfds, npfds, timeout_ms);
 }
 
-void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
-                        const char **phost, const char **pdisplay_host,
-                        int *pport)
+void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
+                                const char **phost, int *pport)
 {
-  struct Curl_cfilter *cf;
+  struct Curl_cfilter *cf, *cf_proxy = NULL;
 
   DEBUGASSERT(data->conn);
   cf = data->conn->cfilter[sockindex];
-  if(cf) {
-    cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
+  /* Find the "lowest" tunneling proxy filter that has not connected yet. */
+  while(cf && !cf->connected) {
+    if((cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) ==
+       (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY))
+       cf_proxy = cf;
+    cf = cf->next;
   }
-  else {
-    /* Some filter ask during shutdown for this, mainly for debugging
-     * purposes. We hand out the defaults, however this is not always
-     * accurate, as the connection might be tunneled, etc. But all that
-     * state is already gone here. */
+  /* cf_proxy (!= NULL) is not connected yet. It is talking
+   * to an interim host and any authentication or other things apply
+   * to this interim host and port. */
+  if(!cf_proxy || cf_proxy->cft->query(cf_proxy, data, CF_QUERY_HOST_PORT,
+                                       pport, CURL_UNCONST(phost))) {
+    /* Everything connected or query unsuccessful, the overall
+     * connection's destination is the answer */
     *phost = data->conn->host.name;
-    *pdisplay_host = data->conn->host.dispname;
     *pport = data->conn->remote_port;
   }
 }
 
 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
-                                struct Curl_easy *data,
-                                int event, int arg1, void *arg2)
+                           struct Curl_easy *data,
+                           int event, int arg1, void *arg2)
 {
   (void)cf;
   (void)data;
@@ -738,6 +801,26 @@
   return CURL_SOCKET_BAD;
 }
 
+unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data)
+{
+  int transport = 0;
+  if(cf && !cf->cft->query(cf, data, CF_QUERY_TRANSPORT, &transport, NULL))
+    return (unsigned char)transport;
+  return (unsigned char)(data->conn ? data->conn->transport_wanted : 0);
+}
+
+static const struct Curl_sockaddr_ex *
+cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+  const struct Curl_sockaddr_ex *remote_addr = NULL;
+  if(cf &&
+     !cf->cft->query(cf, data, CF_QUERY_REMOTE_ADDR, NULL,
+                     CURL_UNCONST(&remote_addr)))
+    return remote_addr;
+  return NULL;
+}
+
 CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   int *is_ipv6, struct ip_quadruple *ipquad)
@@ -760,6 +843,13 @@
   return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
 }
 
+const struct Curl_sockaddr_ex *
+Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex)
+{
+  struct Curl_cfilter *cf = data->conn ? data->conn->cfilter[sockindex] : NULL;
+  return cf ? cf_get_remote_addr(cf, data) : NULL;
+}
+
 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
 {
   if(data->conn) {
@@ -878,8 +968,8 @@
 }
 
 size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
-                                     struct connectdata *conn,
-                                     int sockindex)
+                                    struct connectdata *conn,
+                                    int sockindex)
 {
   CURLcode result;
   int n = 0;
@@ -912,17 +1002,14 @@
 }
 
 CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
-                        char *buf, size_t blen, ssize_t *n)
+                        char *buf, size_t blen, size_t *pnread)
 {
-  CURLcode result = CURLE_OK;
-  ssize_t nread;
-
+  DEBUGASSERT(data);
   DEBUGASSERT(data->conn);
-  nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
-  DEBUGASSERT(nread >= 0 || result);
-  DEBUGASSERT(nread < 0 || !result);
-  *n = (nread >= 0) ? (size_t)nread : 0;
-  return result;
+  if(data && data->conn && data->conn->recv[sockindex])
+    return data->conn->recv[sockindex](data, sockindex, buf, blen, pnread);
+  *pnread = 0;
+  return CURLE_FAILED_INIT;
 }
 
 CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
@@ -930,15 +1017,10 @@
                         size_t *pnwritten)
 {
   size_t write_len = blen;
-  ssize_t nwritten;
-  CURLcode result = CURLE_OK;
-  struct connectdata *conn;
 
-  DEBUGASSERT(sockindex >= 0 && sockindex < 2);
-  DEBUGASSERT(pnwritten);
   DEBUGASSERT(data);
   DEBUGASSERT(data->conn);
-  conn = data->conn;
+  DEBUGASSERT(sockindex >= 0 && sockindex < 2);
 #ifdef DEBUGBUILD
   if(write_len) {
     /* Allow debug builds to override this logic to force short sends
@@ -953,11 +1035,11 @@
 #endif
   if(write_len != blen)
     eos = FALSE;
-  nwritten = conn->send[sockindex](data, sockindex, buf, write_len, eos,
-                                   &result);
-  DEBUGASSERT((nwritten >= 0) || result);
-  *pnwritten = (nwritten < 0) ? 0 : (size_t)nwritten;
-  return result;
+  if(data && data->conn && data->conn->send[sockindex])
+    return data->conn->send[sockindex](data, sockindex, buf, write_len, eos,
+                                       pnwritten);
+  *pnwritten = 0;
+  return CURLE_FAILED_INIT;
 }
 
 void Curl_pollset_reset(struct Curl_easy *data,
@@ -974,8 +1056,8 @@
  *
  */
 void Curl_pollset_change(struct Curl_easy *data,
-                       struct easy_pollset *ps, curl_socket_t sock,
-                       int add_flags, int remove_flags)
+                         struct easy_pollset *ps, curl_socket_t sock,
+                         int add_flags, int remove_flags)
 {
   unsigned int i;
 
@@ -1085,3 +1167,16 @@
   }
   *pwant_read = *pwant_write = FALSE;
 }
+
+bool Curl_pollset_want_read(struct Curl_easy *data,
+                            struct easy_pollset *ps,
+                            curl_socket_t sock)
+{
+  unsigned int i;
+  (void)data;
+  for(i = 0; i < ps->num; ++i) {
+    if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN))
+      return TRUE;
+  }
+  return FALSE;
+}
diff --git a/Utilities/cmcurl/lib/cfilters.h b/Utilities/cmcurl/lib/cfilters.h
index 4c604db..39d906d 100644
--- a/Utilities/cmcurl/lib/cfilters.h
+++ b/Utilities/cmcurl/lib/cfilters.h
@@ -26,11 +26,13 @@
 
 #include "curlx/timediff.h"
 
+struct bufq;
 struct Curl_cfilter;
 struct Curl_easy;
 struct Curl_dns_entry;
 struct connectdata;
 struct ip_quadruple;
+struct curl_tlssessioninfo;
 
 /* Callback to destroy resources held by this filter instance.
  * Implementations MUST NOT chain calls to cf->next.
@@ -53,23 +55,6 @@
                                   struct Curl_easy *data,
                                   bool *done);
 
-/* Return the hostname and port the connection goes to.
- * This may change with the connection state of filters when tunneling
- * is involved.
- * @param cf     the filter to ask
- * @param data   the easy handle currently active
- * @param phost  on return, points to the relevant, real hostname.
- *               this is owned by the connection.
- * @param pdisplay_host  on return, points to the printable hostname.
- *               this is owned by the connection.
- * @param pport  on return, contains the port number
- */
-typedef void     Curl_cft_get_host(struct Curl_cfilter *cf,
-                                   struct Curl_easy *data,
-                                   const char **phost,
-                                   const char **pdisplay_host,
-                                   int *pport);
-
 struct easy_pollset;
 
 /* Passing in an easy_pollset for monitoring of sockets, let
@@ -102,18 +87,18 @@
 typedef bool     Curl_cft_data_pending(struct Curl_cfilter *cf,
                                        const struct Curl_easy *data);
 
-typedef ssize_t  Curl_cft_send(struct Curl_cfilter *cf,
+typedef CURLcode Curl_cft_send(struct Curl_cfilter *cf,
                                struct Curl_easy *data, /* transfer */
                                const void *buf,        /* data to write */
                                size_t len,             /* amount to write */
                                bool eos,               /* last chunk */
-                               CURLcode *err);         /* error to return */
+                               size_t *pnwritten);     /* how much sent */
 
-typedef ssize_t  Curl_cft_recv(struct Curl_cfilter *cf,
+typedef CURLcode Curl_cft_recv(struct Curl_cfilter *cf,
                                struct Curl_easy *data, /* transfer */
                                char *buf,              /* store data here */
                                size_t len,             /* amount to read */
-                               CURLcode *err);         /* error to return */
+                               size_t *pnread);        /* how much received */
 
 typedef bool     Curl_cft_conn_is_alive(struct Curl_cfilter *cf,
                                         struct Curl_easy *data,
@@ -166,6 +151,13 @@
  * - CF_QUERY_NEED_FLUSH: TRUE iff any of the filters have unsent data
  * - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the
  *                   ip quadruple
+ * - CF_QUERY_HOST_PORT: the remote hostname and port a filter talks to
+ * - CF_QUERY_SSL_INFO: fill out the passed curl_tlssessioninfo with the
+ *                      internal from the SSL secured connection when
+ *                      available.
+ * - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX
+ *                      when available, or the same internal pointer
+ *                      when the TLS stack does not differentiate.
  */
 /*      query                             res1       res2     */
 #define CF_QUERY_MAX_CONCURRENT     1  /* number     -        */
@@ -177,6 +169,13 @@
 #define CF_QUERY_NEED_FLUSH         7  /* TRUE/FALSE - */
 #define CF_QUERY_IP_INFO            8  /* TRUE/FALSE struct ip_quadruple */
 #define CF_QUERY_HTTP_VERSION       9  /* number (10/11/20/30)   -  */
+/* pass in a `const struct Curl_sockaddr_ex **` as `pres2`. Gets set
+ * to NULL when not connected. */
+#define CF_QUERY_REMOTE_ADDR       10  /* -          `Curl_sockaddr_ex *` */
+#define CF_QUERY_HOST_PORT         11  /* port       const char * */
+#define CF_QUERY_SSL_INFO          12  /* -    struct curl_tlssessioninfo * */
+#define CF_QUERY_SSL_CTX_INFO      13  /* -    struct curl_tlssessioninfo * */
+#define CF_QUERY_TRANSPORT         14  /* TRNSPRT_*  - * */
 
 /**
  * Query the cfilter for properties. Filters ignorant of a query will
@@ -213,7 +212,6 @@
   Curl_cft_connect *do_connect;           /* establish connection */
   Curl_cft_close *do_close;               /* close conn */
   Curl_cft_shutdown *do_shutdown;         /* shutdown conn */
-  Curl_cft_get_host *get_host;            /* host filter talks to */
   Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
   Curl_cft_data_pending *has_data_pending;/* conn has data pending */
   Curl_cft_send *do_send;                 /* send data */
@@ -241,19 +239,16 @@
 
 /* Default implementations for the type functions, implementing pass-through
  * the filter chain. */
-void     Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              const char **phost, const char **pdisplay_host,
-                              int *pport);
 void     Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
                                     struct Curl_easy *data,
                                     struct easy_pollset *ps);
 bool     Curl_cf_def_data_pending(struct Curl_cfilter *cf,
                                   const struct Curl_easy *data);
-ssize_t  Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
                           const void *buf, size_t len, bool eos,
-                          CURLcode *err);
-ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          char *buf, size_t len, CURLcode *err);
+                          size_t *pnwritten);
+CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          char *buf, size_t len, size_t *pnread);
 CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            int event, int arg1, void *arg2);
@@ -326,11 +321,11 @@
                               struct Curl_easy *data,
                               bool *done);
 void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
-ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          const void *buf, size_t len, bool eos,
-                          CURLcode *err);
-ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          char *buf, size_t len, CURLcode *err);
+CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           const void *buf, size_t len, bool eos,
+                           size_t *pnwritten);
+CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           char *buf, size_t len, size_t *pnread);
 CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
                             struct Curl_easy *data,
                             bool ignore_result,
@@ -356,6 +351,9 @@
 bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
                               struct Curl_easy *data);
 
+unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
+                                         struct Curl_easy *data);
+
 #define CURL_CF_SSL_DEFAULT  -1
 #define CURL_CF_SSL_DISABLE  0
 #define CURL_CF_SSL_ENABLE   1
@@ -395,6 +393,15 @@
  */
 bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
 
+/*
+ * Fill `info` with information about the TLS instance securing
+ * the connection when available, otherwise e.g. when
+ * Curl_conn_is_ssl() is FALSE, return FALSE.
+ */
+bool Curl_conn_get_ssl_info(struct Curl_easy *data,
+                            struct connectdata *conn, int sockindex,
+                            struct curl_tlssessioninfo *info);
+
 /**
  * Connection provides multiplexing of easy handles at `socketindex`.
  */
@@ -407,6 +414,10 @@
 unsigned char Curl_conn_http_version(struct Curl_easy *data,
                                      struct connectdata *conn);
 
+/* Get the TRNSPRT_* the connection is using */
+unsigned char Curl_conn_get_transport(struct Curl_easy *data,
+                                      struct connectdata *conn);
+
 /**
  * Close the filter chain at `sockindex` for connection `data->conn`.
   * Filters remain in place and may be connected again afterwards.
@@ -444,13 +455,17 @@
  */
 curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex);
 
+/* Return a pointer to the connected socket address or NULL. */
+const struct Curl_sockaddr_ex *
+Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex);
+
 /**
  * Tell filters to forget about the socket at sockindex.
  */
 void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex);
 
 /**
- * Adjust the pollset for the filter chain startgin at `cf`.
+ * Adjust the pollset for the filter chain starting at `cf`.
  */
 void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
@@ -475,20 +490,41 @@
 /**
  * Receive data through the filter chain at `sockindex` for connection
  * `data->conn`. Copy at most `len` bytes into `buf`. Return the
- * actual number of bytes copied or a negative value on error.
- * The error code is placed into `*code`.
+ * actual number of bytes copied in `*pnread`or an error.
  */
-ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
-                     size_t len, CURLcode *code);
+CURLcode Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
+                      size_t len, size_t *pnread);
 
 /**
  * Send `len` bytes of data from `buf` through the filter chain `sockindex`
  * at connection `data->conn`. Return the actual number of bytes written
- * or a negative value on error.
- * The error code is placed into `*code`.
+ * in `*pnwritten` or on error.
  */
-ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
-                     const void *buf, size_t len, bool eos, CURLcode *code);
+CURLcode Curl_cf_send(struct Curl_easy *data, int sockindex,
+                      const void *buf, size_t len, bool eos,
+                      size_t *pnwritten);
+
+/**
+ * Receive bytes from connection filter `cf` into `bufq`.
+ * Convenience wrappter around `Curl_bufq_sipn()`,
+ * so users do not have to implement a callback.
+ */
+CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct bufq *bufq,
+                           size_t maxlen,
+                           size_t *pnread);
+
+/**
+ * Send bytes in `bufq` using connection filter `cf`.
+ * A convenience wrapper around `Curl_bufq_write_pass()`,
+ * so users do not have to implement a callback.
+ */
+CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct bufq *bufq,
+                           const unsigned char *buf, size_t blen,
+                           size_t *pnwritten);
 
 /**
  * Notify connection filters that they need to setup data for
@@ -535,9 +571,17 @@
 #ifdef UNITTESTS
 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
 #endif
-void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
-                        const char **phost, const char **pdisplay_host,
-                        int *pport);
+
+/**
+ * Get the remote hostname and port that the connection is currently
+ * talking to (or will talk to).
+ * Once connected or before connect starts,
+ * it is `conn->host.name` and `conn->remote_port`.
+ * During connect, when tunneling proxies are involved (http or socks),
+ * it will be the name and port the proxy currently negotiates with.
+ */
+void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
+                                const char **phost, int *pport);
 
 /**
  * Get the maximum number of parallel transfers the connection
@@ -567,7 +611,7 @@
  */
 CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
                         char *buf, size_t buffersize,
-                        ssize_t *pnread);
+                        size_t *pnread);
 
 /*
  * Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
@@ -622,6 +666,13 @@
                         bool *pwant_read, bool *pwant_write);
 
 /**
+ * Return TRUE if the pollset contains socket with CURL_POLL_IN.
+ */
+bool Curl_pollset_want_read(struct Curl_easy *data,
+                            struct easy_pollset *ps,
+                            curl_socket_t sock);
+
+/**
  * Types and macros used to keep the current easy handle in filter calls,
  * allowing for nested invocations. See #10336.
  *
diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
index f5e2ea8..fd6776e 100644
--- a/Utilities/cmcurl/lib/conncache.c
+++ b/Utilities/cmcurl/lib/conncache.c
@@ -42,7 +42,6 @@
 #include "sigpipe.h"
 #include "connect.h"
 #include "select.h"
-#include "strcase.h"
 #include "curlx/strparse.h"
 #include "uint-table.h"
 
diff --git a/Utilities/cmcurl/lib/conncache.h b/Utilities/cmcurl/lib/conncache.h
index 1314b65..ac07111 100644
--- a/Utilities/cmcurl/lib/conncache.h
+++ b/Utilities/cmcurl/lib/conncache.h
@@ -106,7 +106,7 @@
  * Find a connection in the pool matching `destination`.
  * All callbacks are invoked while the pool's lock is held.
  * @param data        current transfer
- * @param destination match agaonst `conn->destination` in pool
+ * @param destination match against `conn->destination` in pool
  * @param conn_cb     must be present, called for each connection in the
  *                    bundle until it returns TRUE
  * @return combined result of last conn_db and result_cb or FALSE if no
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index 1dcdde3..ac16c33 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -66,7 +66,7 @@
 #include "url.h" /* for Curl_safefree() */
 #include "multiif.h"
 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "inet_ntop.h"
+#include "curlx/inet_ntop.h"
 #include "curlx/inet_pton.h"
 #include "vtls/vtls.h" /* for vtsl cfilters */
 #include "progress.h"
@@ -78,7 +78,6 @@
 #include "vquic/vquic.h" /* for quic cfilters */
 #include "http_proxy.h"
 #include "socks.h"
-#include "strcase.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -90,15 +89,15 @@
 enum alpnid Curl_alpn2alpnid(const char *name, size_t len)
 {
   if(len == 2) {
-    if(strncasecompare(name, "h1", 2))
+    if(curl_strnequal(name, "h1", 2))
       return ALPN_h1;
-    if(strncasecompare(name, "h2", 2))
+    if(curl_strnequal(name, "h2", 2))
       return ALPN_h2;
-    if(strncasecompare(name, "h3", 2))
+    if(curl_strnequal(name, "h3", 2))
       return ALPN_h3;
   }
   else if(len == 8) {
-    if(strncasecompare(name, "http/1.1", 8))
+    if(curl_strnequal(name, "http/1.1", 8))
       return ALPN_h1;
   }
   return ALPN_none; /* unknown, probably rubbish input */
@@ -172,11 +171,11 @@
   }
   data->conn->shutdown.start[sockindex] = *nowp;
   data->conn->shutdown.timeout_ms = (timeout_ms > 0) ?
-    (unsigned int)timeout_ms :
+    (timediff_t)timeout_ms :
     ((data->set.shutdowntimeout > 0) ?
      data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
   /* Set a timer, unless we operate on the admin handle */
-  if(data->mid && data->conn->shutdown.timeout_ms)
+  if(data->mid && (data->conn->shutdown.timeout_ms > 0))
     Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms,
                    EXPIRE_SHUTDOWN);
 }
@@ -187,7 +186,8 @@
   struct curltime now;
   timediff_t left_ms;
 
-  if(!conn->shutdown.start[sockindex].tv_sec || !conn->shutdown.timeout_ms)
+  if(!conn->shutdown.start[sockindex].tv_sec ||
+     (conn->shutdown.timeout_ms <= 0))
     return 0; /* not started or no limits */
 
   if(!nowp) {
@@ -254,8 +254,8 @@
   return NULL;
 }
 
-/* retrieves ip address and port from a sockaddr structure.
-   note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
+/* retrieves ip address and port from a sockaddr structure. note it calls
+   curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
 bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
                       char *addr, int *port)
 {
@@ -272,7 +272,7 @@
   switch(sa->sa_family) {
     case AF_INET:
       si = (struct sockaddr_in *)(void *) sa;
-      if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
+      if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
         unsigned short us_port = ntohs(si->sin_port);
         *port = us_port;
         return TRUE;
@@ -281,7 +281,8 @@
 #ifdef USE_IPV6
     case AF_INET6:
       si6 = (struct sockaddr_in6 *)(void *) sa;
-      if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) {
+      if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr,
+                         MAX_IPADR_LEN)) {
         unsigned short us_port = ntohs(si6->sin6_port);
         *port = us_port;
         return TRUE;
@@ -389,7 +390,6 @@
   expire_id timeout_id;              /* ID for Curl_expire() */
   CURLcode result;
   int error;
-  BIT(rewinded);                     /* if we rewinded the addr list */
   BIT(has_started);                  /* attempts have started */
   BIT(is_done);                      /* out of addresses/time */
   BIT(connected);                    /* cf has connected */
@@ -455,7 +455,7 @@
 }
 
 static void baller_close(struct eyeballer *baller,
-                          struct Curl_easy *data)
+                         struct Curl_easy *data)
 {
   if(baller && baller->cf) {
     Curl_conn_cf_discard_chain(&baller->cf, data);
@@ -463,7 +463,7 @@
 }
 
 static void baller_free(struct eyeballer *baller,
-                         struct Curl_easy *data)
+                        struct Curl_easy *data)
 {
   if(baller) {
     baller_close(baller, data);
@@ -473,7 +473,6 @@
 
 static void baller_rewind(struct eyeballer *baller)
 {
-  baller->rewinded = TRUE;
   baller->addr = baller->first;
   baller->inconclusive = FALSE;
 }
@@ -682,7 +681,7 @@
         /* next attempt was started */
         CURL_TRC_CF(data, cf, "%s trying next", baller->name);
         ++ongoing;
-        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+        Curl_multi_mark_dirty(data);
       }
     }
   }
@@ -832,7 +831,7 @@
     addr1 = addr_first_match(dns->addr, ai_family1);
     /* no ip address families, probably AF_UNIX or something, use the
      * address family given to us */
-    if(!addr1  && !addr0 && dns->addr) {
+    if(!addr1 && !addr0 && dns->addr) {
       ai_family0 = dns->addr->ai_family;
       addr0 = addr_first_match(dns->addr, ai_family0);
     }
@@ -932,8 +931,8 @@
 }
 
 static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  struct easy_pollset *ps)
+                                 struct Curl_easy *data,
+                                 struct easy_pollset *ps)
 {
   struct cf_he_ctx *ctx = cf->ctx;
   size_t i;
@@ -993,11 +992,11 @@
           struct ip_quadruple ipquad;
           int is_ipv6;
           if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
-            const char *host, *disphost;
+            const char *host;
             int port;
-            cf->next->cft->get_host(cf->next, data, &host, &disphost, &port);
+            Curl_conn_get_current_host(data, cf->sockindex, &host, &port);
             CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u",
-                        disphost, ipquad.remote_ip, ipquad.remote_port);
+                        host, ipquad.remote_ip, ipquad.remote_port);
           }
         }
         data->info.numconnects++; /* to track the # of connections made */
@@ -1046,8 +1045,8 @@
 }
 
 static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
-                                          struct Curl_easy *data,
-                                          int query)
+                                           struct Curl_easy *data,
+                                           int query)
 {
   struct cf_he_ctx *ctx = cf->ctx;
   struct curltime t, tmax;
@@ -1134,7 +1133,6 @@
   cf_he_connect,
   cf_he_close,
   cf_he_shutdown,
-  Curl_cf_def_get_host,
   cf_he_adjust_pollset,
   cf_he_data_pending,
   Curl_cf_def_send,
@@ -1398,7 +1396,6 @@
   cf_setup_connect,
   cf_setup_close,
   Curl_cf_def_shutdown,
-  Curl_cf_def_get_host,
   Curl_cf_def_adjust_pollset,
   Curl_cf_def_data_pending,
   Curl_cf_def_send,
@@ -1518,7 +1515,8 @@
 
   /* Still no cfilter set, apply default. */
   if(!conn->cfilter[sockindex]) {
-    result = cf_setup_add(data, conn, sockindex, conn->transport, ssl_mode);
+    result = cf_setup_add(data, conn, sockindex,
+                          conn->transport_wanted, ssl_mode);
     if(result)
       goto out;
   }
diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c
index ac80478..b29e80d 100644
--- a/Utilities/cmcurl/lib/content_encoding.c
+++ b/Utilities/cmcurl/lib/content_encoding.c
@@ -52,7 +52,6 @@
 #include "http.h"
 #include "content_encoding.h"
 #include "strdup.h"
-#include "strcase.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -343,7 +342,7 @@
 }
 
 static void gzip_do_close(struct Curl_easy *data,
-                              struct Curl_cwriter *writer)
+                          struct Curl_cwriter *writer)
 {
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
@@ -464,7 +463,7 @@
 }
 
 static void brotli_do_close(struct Curl_easy *data,
-                                struct Curl_cwriter *writer)
+                            struct Curl_cwriter *writer)
 {
   struct brotli_writer *bp = (struct brotli_writer *) writer;
   (void) data;
@@ -567,7 +566,7 @@
 }
 
 static void zstd_do_close(struct Curl_easy *data,
-                              struct Curl_cwriter *writer)
+                          struct Curl_cwriter *writer)
 {
   struct zstd_writer *zp = (struct zstd_writer *) writer;
   (void)data;
@@ -636,7 +635,7 @@
 
   for(cep = general_unencoders; *cep; cep++) {
     ce = *cep;
-    if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
+    if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT))
       len += strlen(ce->name) + 2;
   }
 
@@ -648,7 +647,7 @@
     char *p = buf;
     for(cep = general_unencoders; *cep; cep++) {
       ce = *cep;
-      if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
+      if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT)) {
         strcpy(p, ce->name);
         p += strlen(p);
         *p++ = ',';
@@ -688,7 +687,7 @@
 }
 
 static void error_do_close(struct Curl_easy *data,
-                               struct Curl_cwriter *writer)
+                           struct Curl_cwriter *writer)
 {
   (void) data;
   (void) writer;
@@ -713,8 +712,8 @@
   if(phase == CURL_CW_TRANSFER_DECODE) {
     for(cep = transfer_unencoders; *cep; cep++) {
       const struct Curl_cwtype *ce = *cep;
-      if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
-         (ce->alias && strncasecompare(name, ce->alias, len)
+      if((curl_strnequal(name, ce->name, len) && !ce->name[len]) ||
+         (ce->alias && curl_strnequal(name, ce->alias, len)
                     && !ce->alias[len]))
         return ce;
     }
@@ -722,8 +721,8 @@
   /* look among the general decoders */
   for(cep = general_unencoders; *cep; cep++) {
     const struct Curl_cwtype *ce = *cep;
-    if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
-       (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
+    if((curl_strnequal(name, ce->name, len) && !ce->name[len]) ||
+       (ce->alias && curl_strnequal(name, ce->alias, len) && !ce->alias[len]))
       return ce;
   }
   return NULL;
@@ -761,12 +760,12 @@
       CURL_TRC_WRITE(data, "looking for %s decoder: %.*s",
                      is_transfer ? "transfer" : "content", (int)namelen, name);
       is_chunked = (is_transfer && (namelen == 7) &&
-                    strncasecompare(name, "chunked", 7));
+                    curl_strnequal(name, "chunked", 7));
       /* if we skip the decoding in this phase, do not look further.
        * Exception is "chunked" transfer-encoding which always must happen */
       if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
          (!is_transfer && data->set.http_ce_skip)) {
-        bool is_identity = strncasecompare(name, "identity", 8);
+        bool is_identity = curl_strnequal(name, "identity", 8);
         /* not requested, ignore */
         CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s",
                        (int)namelen, name);
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index 1a8426c..9221871 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/cookie.c
@@ -135,9 +135,9 @@
   if(hostname_len < cookie_domain_len)
     return FALSE;
 
-  if(!strncasecompare(cookie_domain,
-                      hostname + hostname_len-cookie_domain_len,
-                      cookie_domain_len))
+  if(!curl_strnequal(cookie_domain,
+                     hostname + hostname_len-cookie_domain_len,
+                     cookie_domain_len))
     return FALSE;
 
   /*
@@ -409,7 +409,7 @@
 /* Make sure domain contains a dot or is localhost. */
 static bool bad_domain(const char *domain, size_t len)
 {
-  if((len == 9) && strncasecompare(domain, "localhost", 9))
+  if((len == 9) && curl_strnequal(domain, "localhost", 9))
     return FALSE;
   else {
     /* there must be a dot present, but that dot must not be a trailing dot */
@@ -815,7 +815,7 @@
        * domain can access the variable. Set TRUE when the cookie says
        * .example.com and to false when the domain is complete www.example.com
        */
-      co->tailmatch = !!strncasecompare(ptr, "TRUE", len);
+      co->tailmatch = !!curl_strnequal(ptr, "TRUE", len);
       break;
     case 2:
       /* The file format allows the path field to remain not filled in */
@@ -842,7 +842,7 @@
       FALLTHROUGH();
     case 3:
       co->secure = FALSE;
-      if(strncasecompare(ptr, "TRUE", len)) {
+      if(curl_strnequal(ptr, "TRUE", len)) {
         if(secure || ci->running)
           co->secure = TRUE;
         else
@@ -859,9 +859,9 @@
         return CERR_OUT_OF_MEMORY;
       else {
         /* For Netscape file format cookies we check prefix on the name */
-        if(strncasecompare("__Secure-", co->name, 9))
+        if(curl_strnequal("__Secure-", co->name, 9))
           co->prefix_secure = TRUE;
-        else if(strncasecompare("__Host-", co->name, 7))
+        else if(curl_strnequal("__Host-", co->name, 7))
           co->prefix_host = TRUE;
       }
       break;
@@ -917,7 +917,7 @@
         Curl_psl_release(data);
       }
       else
-        infof(data, "libpsl problem, rejecting cookie for satety");
+        infof(data, "libpsl problem, rejecting cookie for safety");
     }
 
     if(!acceptable) {
@@ -954,7 +954,7 @@
       bool matching_domains = FALSE;
 
       if(clist->domain && co->domain) {
-        if(strcasecompare(clist->domain, co->domain))
+        if(curl_strequal(clist->domain, co->domain))
           /* The domains are identical */
           matching_domains = TRUE;
       }
@@ -981,7 +981,7 @@
         else
           cllen = strlen(clist->spath);
 
-        if(strncasecompare(clist->spath, co->spath, cllen)) {
+        if(curl_strnequal(clist->spath, co->spath, cllen)) {
           infof(data, "cookie '%s' for domain '%s' dropped, would "
                 "overlay an existing cookie", co->name, co->domain);
           return CERR_BAD_SECURE;
@@ -993,7 +993,7 @@
       /* the names are identical */
 
       if(clist->domain && co->domain) {
-        if(strcasecompare(clist->domain, co->domain) &&
+        if(curl_strequal(clist->domain, co->domain) &&
           (clist->tailmatch == co->tailmatch))
           /* The domains are identical */
           replace_old = TRUE;
@@ -1005,7 +1005,7 @@
         /* the domains were identical */
 
         if(clist->spath && co->spath &&
-           !strcasecompare(clist->spath, co->spath))
+           !curl_strequal(clist->spath, co->spath))
           replace_old = FALSE;
         else if(!clist->spath != !co->spath)
           replace_old = FALSE;
@@ -1337,7 +1337,7 @@
       if(!co->domain ||
          (co->tailmatch && !is_ip &&
           cookie_tailmatch(co->domain, strlen(co->domain), host)) ||
-         ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
+         ((!co->tailmatch || is_ip) && curl_strequal(host, co->domain)) ) {
         /*
          * the right part of the host matches the domain stuff in the
          * cookie data
diff --git a/Utilities/cmcurl/lib/cshutdn.c b/Utilities/cmcurl/lib/cshutdn.c
index f05b87d..c8b40dc 100644
--- a/Utilities/cmcurl/lib/cshutdn.c
+++ b/Utilities/cmcurl/lib/cshutdn.c
@@ -40,7 +40,6 @@
 #include "sigpipe.h"
 #include "connect.h"
 #include "select.h"
-#include "strcase.h"
 #include "curlx/strparse.h"
 
 /* The last 3 #include files should be in this order */
@@ -54,12 +53,6 @@
 {
   if(!conn->bits.shutdown_handler) {
 
-    /* Cleanup NTLM connection-related data */
-    Curl_http_auth_cleanup_ntlm(conn);
-
-    /* Cleanup NEGOTIATE connection-related data */
-    Curl_http_auth_cleanup_negotiate(conn);
-
     if(conn->handler && conn->handler->disconnect) {
       /* Some disconnect handlers do a blocking wait on server responses.
        * FTP/IMAP/SMTP and SFTP are among them. When using the internal
@@ -121,8 +114,8 @@
 }
 
 void Curl_cshutdn_run_once(struct Curl_easy *data,
-                      struct connectdata *conn,
-                      bool *done)
+                           struct connectdata *conn,
+                           bool *done)
 {
   DEBUGASSERT(!data->conn);
   Curl_attach_connection(data, conn);
@@ -219,8 +212,8 @@
 #define NUM_POLLS_ON_STACK 10
 
 static CURLcode cshutdn_wait(struct cshutdn *cshutdn,
-                               struct Curl_easy *data,
-                               int timeout_ms)
+                             struct Curl_easy *data,
+                             int timeout_ms)
 {
   struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
   struct curl_pollfds cpfds;
@@ -241,7 +234,7 @@
 
 
 static void cshutdn_perform(struct cshutdn *cshutdn,
-                              struct Curl_easy *data)
+                            struct Curl_easy *data)
 {
   struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
   struct Curl_llist_node *enext;
@@ -402,8 +395,8 @@
 
 
 static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn,
-                                     struct Curl_easy *data,
-                                     struct connectdata *conn)
+                                   struct Curl_easy *data,
+                                   struct connectdata *conn)
 {
   CURLMcode mresult;
 
@@ -418,8 +411,8 @@
 
 
 void Curl_cshutdn_add(struct cshutdn *cshutdn,
-                        struct connectdata *conn,
-                        size_t conns_in_pool)
+                      struct connectdata *conn,
+                      size_t conns_in_pool)
 {
   struct Curl_easy *data = cshutdn->multi->admin;
   size_t max_total = (cshutdn->multi->max_total_connections > 0) ?
@@ -451,8 +444,8 @@
 
 
 static void cshutdn_multi_socket(struct cshutdn *cshutdn,
-                                   struct Curl_easy *data,
-                                   curl_socket_t s)
+                                 struct Curl_easy *data,
+                                 curl_socket_t s)
 {
   struct Curl_llist_node *e;
   struct connectdata *conn;
diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
index 5e942a8..0c94168 100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -581,18 +581,9 @@
 /* Define to 1 if you have the <sys/select.h> header file. */
 #cmakedefine HAVE_SYS_SELECT_H 1
 
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#cmakedefine HAVE_SYS_SOCKET_H 1
-
 /* Define to 1 if you have the <sys/sockio.h> header file. */
 #cmakedefine HAVE_SYS_SOCKIO_H 1
 
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#cmakedefine HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#cmakedefine HAVE_SYS_TIME_H 1
-
 /* Define to 1 if you have the <sys/types.h> header file. */
 #cmakedefine HAVE_SYS_TYPES_H 1
 
@@ -694,18 +685,12 @@
 /* if GnuTLS is enabled */
 #cmakedefine USE_GNUTLS 1
 
-/* if Secure Transport is enabled */
-#cmakedefine USE_SECTRANSP 1
-
 /* if SSL session export support is available */
 #cmakedefine USE_SSLS_EXPORT 1
 
 /* if mbedTLS is enabled */
 #cmakedefine USE_MBEDTLS 1
 
-/* if BearSSL is enabled */
-#cmakedefine USE_BEARSSL 1
-
 /* if Rustls is enabled */
 #cmakedefine USE_RUSTLS 1
 
@@ -806,18 +791,6 @@
 /* Number of bits in a file offset, on hosts where this is settable. */
 #cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
 
-/* Define for large files, on AIX-style hosts. */
-#cmakedefine _LARGE_FILES ${_LARGE_FILES}
-
-/* define this if you need it to compile thread-safe code */
-#cmakedefine _THREAD_SAFE ${_THREAD_SAFE}
-
-/* Define to empty if `const' does not conform to ANSI C. */
-#cmakedefine const ${const}
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-#cmakedefine size_t ${size_t}
-
 /* the signed version of size_t */
 #ifndef SIZEOF_SSIZE_T
 # if SIZEOF_LONG == SIZEOF_SIZE_T
diff --git a/Utilities/cmcurl/lib/curl_des.c b/Utilities/cmcurl/lib/curl_des.c
index 15836f5..a202dd3 100644
--- a/Utilities/cmcurl/lib/curl_des.c
+++ b/Utilities/cmcurl/lib/curl_des.c
@@ -26,7 +26,6 @@
 
 #if defined(USE_CURL_NTLM_CORE) && \
   (defined(USE_GNUTLS) ||          \
-   defined(USE_SECTRANSP) ||       \
    defined(USE_OS400CRYPTO) ||     \
    defined(USE_WIN32_CRYPTO))
 
diff --git a/Utilities/cmcurl/lib/curl_des.h b/Utilities/cmcurl/lib/curl_des.h
index 2dd498d..c50aaf4 100644
--- a/Utilities/cmcurl/lib/curl_des.h
+++ b/Utilities/cmcurl/lib/curl_des.h
@@ -28,7 +28,6 @@
 
 #if defined(USE_CURL_NTLM_CORE) && \
   (defined(USE_GNUTLS) ||          \
-   defined(USE_SECTRANSP) ||       \
    defined(USE_OS400CRYPTO) ||     \
    defined(USE_WIN32_CRYPTO))
 
diff --git a/Utilities/cmcurl/lib/curl_get_line.c b/Utilities/cmcurl/lib/curl_get_line.c
index 2bb5749..4b1c6c3 100644
--- a/Utilities/cmcurl/lib/curl_get_line.c
+++ b/Utilities/cmcurl/lib/curl_get_line.c
@@ -32,6 +32,15 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
+static int appendnl(struct dynbuf *buf)
+{
+  CURLcode result = curlx_dyn_addn(buf, "\n", 1);
+  if(result)
+    /* too long line or out of memory */
+    return 0; /* error */
+  return 1; /* all good */
+}
+
 /*
  * Curl_get_line() makes sure to only return complete whole lines that end
  * newlines.
@@ -43,9 +52,10 @@
   curlx_dyn_reset(buf);
   while(1) {
     char *b = fgets(buffer, sizeof(buffer), input);
+    size_t rlen;
 
     if(b) {
-      size_t rlen = strlen(b);
+      rlen = strlen(b);
 
       if(!rlen)
         break;
@@ -59,19 +69,24 @@
         /* end of the line */
         return 1; /* all good */
 
-      else if(feof(input)) {
+      else if(feof(input))
         /* append a newline */
-        result = curlx_dyn_addn(buf, "\n", 1);
-        if(result)
-          /* too long line or out of memory */
-          return 0; /* error */
+        return appendnl(buf);
+    }
+    else {
+      rlen = curlx_dyn_len(buf);
+      if(rlen) {
+        b = curlx_dyn_ptr(buf);
+
+        if(b[rlen-1] != '\n')
+          /* append a newline */
+          return appendnl(buf);
+
         return 1; /* all good */
       }
+      else
+        break;
     }
-    else if(curlx_dyn_len(buf))
-      return 1; /* all good */
-    else
-      break;
   }
   return 0;
 }
diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c
index f83701a..4690218 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.c
+++ b/Utilities/cmcurl/lib/curl_gssapi.c
@@ -52,17 +52,260 @@
   9, CURL_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")
 };
 
-OM_uint32 Curl_gss_init_sec_context(
-    struct Curl_easy *data,
-    OM_uint32 *minor_status,
-    gss_ctx_id_t *context,
-    gss_name_t target_name,
-    gss_OID mech_type,
-    gss_channel_bindings_t input_chan_bindings,
-    gss_buffer_t input_token,
-    gss_buffer_t output_token,
-    const bool mutual_auth,
-    OM_uint32 *ret_flags)
+#ifdef DEBUGBUILD
+enum min_err_code {
+  STUB_GSS_OK = 0,
+  STUB_GSS_NO_MEMORY,
+  STUB_GSS_INVALID_ARGS,
+  STUB_GSS_INVALID_CREDS,
+  STUB_GSS_INVALID_CTX,
+  STUB_GSS_SERVER_ERR,
+  STUB_GSS_NO_MECH,
+  STUB_GSS_LAST
+};
+
+/* libcurl is also passing this struct to these functions, which are not yet
+ * stubbed:
+ *   gss_inquire_context()
+ *   gss_unwrap()
+ *   gss_wrap()
+ */
+struct stub_gss_ctx_id_t_desc {
+  enum { STUB_GSS_NONE, STUB_GSS_KRB5, STUB_GSS_NTLM1, STUB_GSS_NTLM3 } sent;
+  int have_krb5;
+  int have_ntlm;
+  OM_uint32 flags;
+  char creds[250];
+};
+
+static OM_uint32
+stub_gss_init_sec_context(OM_uint32 *min,
+                          gss_cred_id_t initiator_cred_handle,
+                          struct stub_gss_ctx_id_t_desc **context,
+                          gss_name_t target_name,
+                          const gss_OID mech_type,
+                          OM_uint32 req_flags,
+                          OM_uint32 time_req,
+                          const gss_channel_bindings_t input_chan_bindings,
+                          gss_buffer_desc *input_token,
+                          gss_OID *actual_mech_type,
+                          gss_buffer_desc *output_token,
+                          OM_uint32 *ret_flags,
+                          OM_uint32 *time_rec)
+{
+  struct stub_gss_ctx_id_t_desc *ctx = NULL;
+
+  /* The token will be encoded in base64 */
+  size_t length = sizeof(ctx->creds) * 3 / 4;
+  size_t used = 0;
+  char *token = NULL;
+  const char *creds = NULL;
+
+  (void)initiator_cred_handle;
+  (void)mech_type;
+  (void)time_req;
+  (void)input_chan_bindings;
+  (void)actual_mech_type;
+
+  if(!min)
+    return GSS_S_FAILURE;
+
+  *min = 0;
+
+  if(!context || !target_name || !output_token) {
+    *min = STUB_GSS_INVALID_ARGS;
+    return GSS_S_FAILURE;
+  }
+
+  creds = getenv("CURL_STUB_GSS_CREDS");
+  if(!creds || strlen(creds) >= sizeof(ctx->creds)) {
+    *min = STUB_GSS_INVALID_CREDS;
+    return GSS_S_FAILURE;
+  }
+
+  ctx = *context;
+  if(ctx && strcmp(ctx->creds, creds)) {
+    *min = STUB_GSS_INVALID_CREDS;
+    return GSS_S_FAILURE;
+  }
+
+  output_token->length = 0;
+  output_token->value = NULL;
+
+  if(input_token && input_token->length) {
+    if(!ctx) {
+      *min = STUB_GSS_INVALID_CTX;
+      return GSS_S_FAILURE;
+    }
+
+    /* Server response, either D (RA==) or C (Qw==) */
+    if(((char *) input_token->value)[0] == 'D') {
+      /* Done */
+      switch(ctx->sent) {
+      case STUB_GSS_KRB5:
+      case STUB_GSS_NTLM3:
+        if(ret_flags)
+          *ret_flags = ctx->flags;
+        if(time_rec)
+          *time_rec = GSS_C_INDEFINITE;
+        return GSS_S_COMPLETE;
+      default:
+        *min = STUB_GSS_SERVER_ERR;
+        return GSS_S_FAILURE;
+      }
+    }
+
+    if(((char *) input_token->value)[0] != 'C') {
+      /* We only support Done or Continue */
+      *min = STUB_GSS_SERVER_ERR;
+      return GSS_S_FAILURE;
+    }
+
+    /* Continue */
+    switch(ctx->sent) {
+    case STUB_GSS_KRB5:
+      /* We sent KRB5 and it failed, let's try NTLM */
+      if(ctx->have_ntlm) {
+        ctx->sent = STUB_GSS_NTLM1;
+        break;
+      }
+      else {
+        *min = STUB_GSS_SERVER_ERR;
+        return GSS_S_FAILURE;
+      }
+    case STUB_GSS_NTLM1:
+      ctx->sent = STUB_GSS_NTLM3;
+      break;
+    default:
+      *min = STUB_GSS_SERVER_ERR;
+      return GSS_S_FAILURE;
+    }
+  }
+  else {
+    if(ctx) {
+      *min = STUB_GSS_INVALID_CTX;
+      return GSS_S_FAILURE;
+    }
+
+    ctx = calloc(1, sizeof(*ctx));
+    if(!ctx) {
+      *min = STUB_GSS_NO_MEMORY;
+      return GSS_S_FAILURE;
+    }
+
+    if(strstr(creds, "KRB5"))
+      ctx->have_krb5 = 1;
+
+    if(strstr(creds, "NTLM"))
+      ctx->have_ntlm = 1;
+
+    if(ctx->have_krb5)
+      ctx->sent = STUB_GSS_KRB5;
+    else if(ctx->have_ntlm)
+      ctx->sent = STUB_GSS_NTLM1;
+    else {
+      free(ctx);
+      *min = STUB_GSS_NO_MECH;
+      return GSS_S_FAILURE;
+    }
+
+    strcpy(ctx->creds, creds);
+    ctx->flags = req_flags;
+  }
+
+  /* To avoid memdebug macro replacement, wrap the name in parentheses to call
+     the original version. It is freed via the GSS API gss_release_buffer(). */
+  token = (malloc)(length);
+  if(!token) {
+    free(ctx);
+    *min = STUB_GSS_NO_MEMORY;
+    return GSS_S_FAILURE;
+  }
+
+  {
+    gss_buffer_desc target_desc;
+    gss_OID name_type = GSS_C_NO_OID;
+    OM_uint32 minor_status;
+    OM_uint32 major_status;
+    major_status = gss_display_name(&minor_status, target_name,
+                                    &target_desc, &name_type);
+    if(GSS_ERROR(major_status)) {
+      (free)(token);
+      free(ctx);
+      *min = STUB_GSS_NO_MEMORY;
+      return GSS_S_FAILURE;
+    }
+
+    if(strlen(creds) + target_desc.length + 5 >= sizeof(ctx->creds)) {
+      (free)(token);
+      free(ctx);
+      *min = STUB_GSS_NO_MEMORY;
+      return GSS_S_FAILURE;
+    }
+
+    /* Token format: creds:target:type:padding */
+    used = msnprintf(token, length, "%s:%.*s:%d:", creds,
+                     (int)target_desc.length, (const char *)target_desc.value,
+                     ctx->sent);
+
+    gss_release_buffer(&minor_status, &target_desc);
+  }
+
+  if(used >= length) {
+    (free)(token);
+    free(ctx);
+    *min = STUB_GSS_NO_MEMORY;
+    return GSS_S_FAILURE;
+  }
+
+  /* Overwrite null-terminator */
+  memset(token + used, 'A', length - used);
+
+  *context = ctx;
+
+  output_token->value = token;
+  output_token->length = length;
+
+  return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+stub_gss_delete_sec_context(OM_uint32 *min,
+                            struct stub_gss_ctx_id_t_desc **context,
+                            gss_buffer_t output_token)
+{
+  (void)output_token;
+
+  if(!min)
+    return GSS_S_FAILURE;
+
+  if(!context) {
+    *min = STUB_GSS_INVALID_CTX;
+    return GSS_S_FAILURE;
+  }
+  if(!*context) {
+    *min = STUB_GSS_INVALID_CTX;
+    return GSS_S_FAILURE;
+  }
+
+  free(*context);
+  *context = NULL;
+  *min = 0;
+
+  return GSS_S_COMPLETE;
+}
+#endif /* DEBUGBUILD */
+
+OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
+                                    OM_uint32 *minor_status,
+                                    gss_ctx_id_t *context,
+                                    gss_name_t target_name,
+                                    gss_OID mech_type,
+                                    gss_channel_bindings_t input_chan_bindings,
+                                    gss_buffer_t input_token,
+                                    gss_buffer_t output_token,
+                                    const bool mutual_auth,
+                                    OM_uint32 *ret_flags)
 {
   OM_uint32 req_flags = GSS_C_REPLAY_FLAG;
 
@@ -74,13 +317,30 @@
     req_flags |= GSS_C_DELEG_POLICY_FLAG;
 #else
     infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
-        "compiled in");
+          "compiled in");
 #endif
   }
 
   if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG)
     req_flags |= GSS_C_DELEG_FLAG;
 
+#ifdef DEBUGBUILD
+  if(getenv("CURL_STUB_GSS_CREDS"))
+    return stub_gss_init_sec_context(minor_status,
+                                     GSS_C_NO_CREDENTIAL, /* cred_handle */
+                                     (struct stub_gss_ctx_id_t_desc **)context,
+                                     target_name,
+                                     mech_type,
+                                     req_flags,
+                                     0, /* time_req */
+                                     input_chan_bindings,
+                                     input_token,
+                                     NULL, /* actual_mech_type */
+                                     output_token,
+                                     ret_flags,
+                                     NULL /* time_rec */);
+#endif /* DEBUGBUILD */
+
   return gss_init_sec_context(minor_status,
                               GSS_C_NO_CREDENTIAL, /* cred_handle */
                               context,
@@ -96,6 +356,20 @@
                               NULL /* time_rec */);
 }
 
+OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min,
+                                      gss_ctx_id_t *context,
+                                      gss_buffer_t output_token)
+{
+#ifdef DEBUGBUILD
+  if(getenv("CURL_STUB_GSS_CREDS"))
+    return stub_gss_delete_sec_context(min,
+                                     (struct stub_gss_ctx_id_t_desc **)context,
+                                     output_token);
+#endif /* DEBUGBUILD */
+
+  return gss_delete_sec_context(min, context, output_token);
+}
+
 #define GSS_LOG_BUFFER_LEN 1024
 static size_t display_gss_error(OM_uint32 status, int type,
                                 char *buf, size_t len) {
diff --git a/Utilities/cmcurl/lib/curl_gssapi.h b/Utilities/cmcurl/lib/curl_gssapi.h
index 7b9a534..2659f23 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.h
+++ b/Utilities/cmcurl/lib/curl_gssapi.h
@@ -32,17 +32,20 @@
 extern gss_OID_desc Curl_krb5_mech_oid;
 
 /* Common method for using GSS-API */
-OM_uint32 Curl_gss_init_sec_context(
-    struct Curl_easy *data,
-    OM_uint32 *minor_status,
-    gss_ctx_id_t *context,
-    gss_name_t target_name,
-    gss_OID mech_type,
-    gss_channel_bindings_t input_chan_bindings,
-    gss_buffer_t input_token,
-    gss_buffer_t output_token,
-    const bool mutual_auth,
-    OM_uint32 *ret_flags);
+OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
+                                    OM_uint32 *minor_status,
+                                    gss_ctx_id_t *context,
+                                    gss_name_t target_name,
+                                    gss_OID mech_type,
+                                    gss_channel_bindings_t input_chan_bindings,
+                                    gss_buffer_t input_token,
+                                    gss_buffer_t output_token,
+                                    const bool mutual_auth,
+                                    OM_uint32 *ret_flags);
+
+OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min,
+                                      gss_ctx_id_t *context_handle,
+                                      gss_buffer_t output_token);
 
 /* Helper to log a GSS-API error status */
 void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h
index bc3e944..b4536c1 100644
--- a/Utilities/cmcurl/lib/curl_memory.h
+++ b/Utilities/cmcurl/lib/curl_memory.h
@@ -57,7 +57,6 @@
 #ifdef HEADER_CURL_MEMDEBUG_H
 /* cleanup after memdebug.h */
 
-#ifdef MEMDEBUG_NODEFINES
 #ifdef CURLDEBUG
 
 #undef strdup
@@ -69,28 +68,28 @@
 #undef recv
 
 #ifdef _WIN32
-#  ifdef UNICODE
-#    undef wcsdup
-#    undef _wcsdup
-#    undef _tcsdup
-#  else
-#    undef _tcsdup
-#  endif
+#undef _tcsdup
 #endif
 
 #undef socket
 #undef accept
+#ifdef HAVE_ACCEPT4
+#undef accept4
+#endif
 #ifdef HAVE_SOCKETPAIR
 #undef socketpair
 #endif
 
 /* sclose is probably already defined, redefine it! */
 #undef sclose
+#define sclose(x)  CURL_SCLOSE(x)
 #undef fopen
+#ifdef CURL_FOPEN
+#define fopen(fname, mode)  CURL_FOPEN(fname, mode)
+#endif
 #undef fdopen
 #undef fclose
 
-#endif /* MEMDEBUG_NODEFINES */
 #endif /* CURLDEBUG */
 
 #undef HEADER_CURL_MEMDEBUG_H
@@ -122,9 +121,6 @@
 extern curl_realloc_callback Curl_crealloc;
 extern curl_strdup_callback Curl_cstrdup;
 extern curl_calloc_callback Curl_ccalloc;
-#if defined(_WIN32) && defined(UNICODE)
-extern curl_wcsdup_callback Curl_cwcsdup;
-#endif
 
 #ifndef CURLDEBUG
 
@@ -149,18 +145,13 @@
 #define free(ptr) Curl_cfree(ptr)
 
 #ifdef _WIN32
-#  ifdef UNICODE
-#    undef wcsdup
-#    define wcsdup(ptr) Curl_cwcsdup(ptr)
-#    undef _wcsdup
-#    define _wcsdup(ptr) Curl_cwcsdup(ptr)
-#    undef _tcsdup
-#    define _tcsdup(ptr) Curl_cwcsdup(ptr)
-#  else
-#    undef _tcsdup
-#    define _tcsdup(ptr) Curl_cstrdup(ptr)
-#  endif
+#undef _tcsdup
+#ifdef UNICODE
+#define _tcsdup(ptr) Curl_wcsdup(ptr)
+#else
+#define _tcsdup(ptr) Curl_cstrdup(ptr)
 #endif
+#endif /* _WIN32 */
 
 #endif /* CURLDEBUG */
 #endif /* HEADER_CURL_MEMORY_H */
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
index d6cd44d..c359531 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.c
@@ -40,9 +40,8 @@
    3. USE_GNUTLS
    4. -
    5. USE_MBEDTLS
-   6. USE_SECTRANSP
-   7. USE_OS400CRYPTO
-   8. USE_WIN32_CRYPTO
+   6. USE_OS400CRYPTO
+   7. USE_WIN32_CRYPTO
 
    This ensures that:
    - the same SSL branch gets activated throughout this source
@@ -107,11 +106,6 @@
 
 #  include <mbedtls/des.h>
 
-#elif defined(USE_SECTRANSP)
-
-#  include <CommonCrypto/CommonCryptor.h>
-#  include <CommonCrypto/CommonDigest.h>
-
 #elif defined(USE_OS400CRYPTO)
 #  include "cipher.mih"  /* mih/cipher */
 #elif defined(USE_WIN32_CRYPTO)
@@ -209,29 +203,6 @@
   return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
 }
 
-#elif defined(USE_SECTRANSP)
-
-static bool encrypt_des(const unsigned char *in, unsigned char *out,
-                        const unsigned char *key_56)
-{
-  char key[8];
-  size_t out_len;
-  CCCryptorStatus err;
-
-  /* Expand the 56-bit key to 64 bits */
-  extend_key_56_to_64(key_56, key);
-
-  /* Set the key parity to odd */
-  Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
-
-  /* Perform the encryption */
-  err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key,
-                kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out,
-                8 /* outbuflen */, &out_len);
-
-  return err == kCCSuccess;
-}
-
 #elif defined(USE_OS400CRYPTO)
 
 static bool encrypt_des(const unsigned char *in, unsigned char *out,
@@ -339,8 +310,8 @@
   des_encrypt(&des, 8, results + 8, plaintext);
   setup_des_key(keys + 14, &des);
   des_encrypt(&des, 8, results + 16, plaintext);
-#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP)            \
-  || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
+#elif defined(USE_MBEDTLS) || defined(USE_OS400CRYPTO) ||       \
+  defined(USE_WIN32_CRYPTO)
   encrypt_des(plaintext, results, keys);
   encrypt_des(plaintext, results + 8, keys + 7);
   encrypt_des(plaintext, results + 16, keys + 14);
@@ -387,8 +358,8 @@
     des_encrypt(&des, 8, lmbuffer, magic);
     setup_des_key(pw + 7, &des);
     des_encrypt(&des, 8, lmbuffer + 8, magic);
-#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP)            \
-  || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
+#elif defined(USE_MBEDTLS) || defined(USE_OS400CRYPTO) ||       \
+  defined(USE_WIN32_CRYPTO)
     encrypt_des(magic, lmbuffer, pw);
     encrypt_des(magic, lmbuffer + 8, pw + 7);
 #endif
@@ -466,7 +437,7 @@
 static void time2filetime(struct ms_filetime *ft, time_t t)
 {
 #if SIZEOF_TIME_T > 4
-  t = (t + CURL_OFF_T_C(11644473600)) * 10000000;
+  t = (t + (curl_off_t)11644473600) * 10000000;
   ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF);
   ft->dwHighDateTime = (unsigned int) (t >> 32);
 #else
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.h b/Utilities/cmcurl/lib/curl_ntlm_core.h
index e2e4b1b..7571ad5 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.h
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.h
@@ -28,6 +28,10 @@
 
 #if defined(USE_CURL_NTLM_CORE)
 
+#include "vauth/vauth.h"
+
+struct ntlmdata;
+
 /* Helpers to generate function byte arguments in little endian order */
 #define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
 #define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c
index 62632c1..0be1f7c 100644
--- a/Utilities/cmcurl/lib/curl_rtmp.c
+++ b/Utilities/cmcurl/lib/curl_rtmp.c
@@ -326,51 +326,54 @@
   return CURLE_OK;
 }
 
-static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
-                         size_t len, CURLcode *err)
+static CURLcode rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
+                          size_t len, size_t *pnread)
 {
   struct connectdata *conn = data->conn;
   RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
+  CURLcode result = CURLE_OK;
   ssize_t nread;
 
   (void)sockindex; /* unused */
-  if(!r) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  *pnread = 0;
+  if(!r)
+    return CURLE_FAILED_INIT;
 
   nread = RTMP_Read(r, buf, curlx_uztosi(len));
   if(nread < 0) {
     if(r->m_read.status == RTMP_READ_COMPLETE ||
        r->m_read.status == RTMP_READ_EOF) {
       data->req.size = data->req.bytecount;
-      nread = 0;
     }
     else
-      *err = CURLE_RECV_ERROR;
+      result = CURLE_RECV_ERROR;
   }
-  return nread;
+  else
+    *pnread = (size_t)nread;
+
+  return result;
 }
 
-static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
-                         const void *buf, size_t len, bool eos, CURLcode *err)
+static CURLcode rtmp_send(struct Curl_easy *data, int sockindex,
+                          const void *buf, size_t len, bool eos,
+                          size_t *pnwritten)
 {
   struct connectdata *conn = data->conn;
   RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
-  ssize_t num;
+  ssize_t nwritten;
 
   (void)sockindex; /* unused */
   (void)eos; /* unused */
-  if(!r) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  *pnwritten = 0;
+  if(!r)
+    return CURLE_FAILED_INIT;
 
-  num = RTMP_Write(r, (const char *)buf, curlx_uztosi(len));
-  if(num < 0)
-    *err = CURLE_SEND_ERROR;
+  nwritten = RTMP_Write(r, (const char *)buf, curlx_uztosi(len));
+  if(nwritten < 0)
+    return CURLE_SEND_ERROR;
 
-  return num;
+  *pnwritten = (size_t)nwritten;
+  return CURLE_OK;
 }
 
 void Curl_rtmp_version(char *version, size_t len)
diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c
index 4fcbaac..766de44 100644
--- a/Utilities/cmcurl/lib/curl_sasl.c
+++ b/Utilities/cmcurl/lib/curl_sasl.c
@@ -77,44 +77,6 @@
 };
 
 /*
- * Curl_sasl_cleanup()
- *
- * This is used to cleanup any libraries or curl modules used by the sasl
- * functions.
- *
- * Parameters:
- *
- * conn     [in]     - The connection data.
- * authused [in]     - The authentication mechanism used.
- */
-void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
-{
-  (void)conn;
-  (void)authused;
-
-#if defined(USE_KERBEROS5)
-  /* Cleanup the gssapi structure */
-  if(authused == SASL_MECH_GSSAPI) {
-    Curl_auth_cleanup_gssapi(&conn->krb5);
-  }
-#endif
-
-#if defined(USE_GSASL)
-  /* Cleanup the GSASL structure */
-  if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
-    Curl_auth_gsasl_cleanup(&conn->gsasl);
-  }
-#endif
-
-#if defined(USE_NTLM)
-  /* Cleanup the NTLM structure */
-  if(authused == SASL_MECH_NTLM) {
-    Curl_auth_cleanup_ntlm(&conn->ntlm);
-  }
-#endif
-}
-
-/*
  * Curl_sasl_decode_mech()
  *
  * Convert a SASL mechanism name into a token.
@@ -334,6 +296,241 @@
   return FALSE;
 }
 
+struct sasl_ctx {
+  struct SASL *sasl;
+  struct connectdata *conn;
+  const char *user;
+  unsigned short enabledmechs;
+  const char *mech;
+  saslstate state1;
+  saslstate state2;
+  struct bufref resp;
+  CURLcode result;
+};
+
+static bool sasl_choose_external(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if((sctx->enabledmechs & SASL_MECH_EXTERNAL) && !sctx->conn->passwd[0]) {
+    sctx->mech = SASL_MECH_STRING_EXTERNAL;
+    sctx->state1 = SASL_EXTERNAL;
+    sctx->sasl->authused = SASL_MECH_EXTERNAL;
+
+    if(sctx->sasl->force_ir || data->set.sasl_ir)
+      Curl_auth_create_external_message(sctx->conn->user, &sctx->resp);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+#ifdef USE_KERBEROS5
+static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if(sctx->user &&
+     (sctx->enabledmechs & SASL_MECH_GSSAPI) &&
+     Curl_auth_is_gssapi_supported() &&
+     Curl_auth_user_contains_domain(sctx->conn->user)) {
+    const char *service = data->set.str[STRING_SERVICE_NAME] ?
+      data->set.str[STRING_SERVICE_NAME] :
+      sctx->sasl->params->service;
+
+    sctx->sasl->mutual_auth = FALSE;
+    sctx->mech = SASL_MECH_STRING_GSSAPI;
+    sctx->state1 = SASL_GSSAPI;
+    sctx->state2 = SASL_GSSAPI_TOKEN;
+    sctx->sasl->authused = SASL_MECH_GSSAPI;
+
+    if(sctx->sasl->force_ir || data->set.sasl_ir) {
+      struct kerberos5data *krb5 = Curl_auth_krb5_get(sctx->conn);
+      sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY :
+        Curl_auth_create_gssapi_user_message(data, sctx->conn->user,
+                                             sctx->conn->passwd,
+                                             service, sctx->conn->host.name,
+                                             sctx->sasl->mutual_auth, NULL,
+                                             krb5, &sctx->resp);
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+#endif /* USE_KERBEROS5 */
+
+#ifdef USE_GSASL
+static bool sasl_choose_gsasl(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  struct gsasldata *gsasl;
+  struct bufref nullmsg;
+
+  if(sctx->user &&
+     (sctx->enabledmechs & (SASL_MECH_SCRAM_SHA_256|SASL_MECH_SCRAM_SHA_1))) {
+    gsasl = Curl_auth_gsasl_get(sctx->conn);
+    if(!gsasl) {
+      sctx->result = CURLE_OUT_OF_MEMORY;
+      return TRUE; /* attempted, but failed */
+    }
+
+    if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
+      Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
+                                   gsasl)) {
+      sctx->mech = SASL_MECH_STRING_SCRAM_SHA_256;
+      sctx->sasl->authused = SASL_MECH_SCRAM_SHA_256;
+    }
+    else if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
+      Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
+                                   gsasl)) {
+      sctx->mech = SASL_MECH_STRING_SCRAM_SHA_1;
+      sctx->sasl->authused = SASL_MECH_SCRAM_SHA_1;
+    }
+    else
+      return FALSE;
+
+    Curl_bufref_init(&nullmsg);
+    sctx->state1 = SASL_GSASL;
+    sctx->state2 = SASL_GSASL;
+    sctx->result = Curl_auth_gsasl_start(data, sctx->conn->user,
+                                         sctx->conn->passwd, gsasl);
+    if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir))
+      sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+#endif /* USE_GSASL */
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+static bool sasl_choose_digest(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  (void)data;
+  if(!sctx->user)
+    return FALSE;
+  else if((sctx->enabledmechs & SASL_MECH_DIGEST_MD5) &&
+     Curl_auth_is_digest_supported()) {
+    sctx->mech = SASL_MECH_STRING_DIGEST_MD5;
+    sctx->state1 = SASL_DIGESTMD5;
+    sctx->sasl->authused = SASL_MECH_DIGEST_MD5;
+    return TRUE;
+  }
+  else if(sctx->enabledmechs & SASL_MECH_CRAM_MD5) {
+    sctx->mech = SASL_MECH_STRING_CRAM_MD5;
+    sctx->state1 = SASL_CRAMMD5;
+    sctx->sasl->authused = SASL_MECH_CRAM_MD5;
+    return TRUE;
+  }
+  return FALSE;
+}
+#endif /* !CURL_DISABLE_DIGEST_AUTH */
+
+#ifdef USE_NTLM
+static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if(!sctx->user)
+    return FALSE;
+  else if((sctx->enabledmechs & SASL_MECH_NTLM) &&
+          Curl_auth_is_ntlm_supported()) {
+    const char *service = data->set.str[STRING_SERVICE_NAME] ?
+      data->set.str[STRING_SERVICE_NAME] :
+      sctx->sasl->params->service;
+    const char *hostname;
+    int port;
+
+    Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
+
+    sctx->mech = SASL_MECH_STRING_NTLM;
+    sctx->state1 = SASL_NTLM;
+    sctx->state2 = SASL_NTLM_TYPE2MSG;
+    sctx->sasl->authused = SASL_MECH_NTLM;
+
+    if(sctx->sasl->force_ir || data->set.sasl_ir) {
+      struct ntlmdata *ntlm = Curl_auth_ntlm_get(sctx->conn, FALSE);
+      sctx->result = !ntlm ? CURLE_OUT_OF_MEMORY :
+        Curl_auth_create_ntlm_type1_message(data,
+                                            sctx->conn->user,
+                                            sctx->conn->passwd,
+                                            service, hostname,
+                                            ntlm, &sctx->resp);
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+#endif /* USE_NTLM */
+
+static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  const char *oauth_bearer = data->set.str[STRING_BEARER];
+
+  if(sctx->user && oauth_bearer &&
+     (sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
+    const char *hostname;
+    int port;
+    Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
+
+    sctx->mech = SASL_MECH_STRING_OAUTHBEARER;
+    sctx->state1 = SASL_OAUTH2;
+    sctx->state2 = SASL_OAUTH2_RESP;
+    sctx->sasl->authused = SASL_MECH_OAUTHBEARER;
+
+    if(sctx->sasl->force_ir || data->set.sasl_ir)
+      sctx->result =
+        Curl_auth_create_oauth_bearer_message(sctx->conn->user,
+                                              hostname, port,
+                                              oauth_bearer, &sctx->resp);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static bool sasl_choose_oauth2(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  const char *oauth_bearer = data->set.str[STRING_BEARER];
+
+  if(sctx->user && oauth_bearer &&
+     (sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
+    sctx->mech = SASL_MECH_STRING_XOAUTH2;
+    sctx->state1 = SASL_OAUTH2;
+    sctx->sasl->authused = SASL_MECH_XOAUTH2;
+
+    if(sctx->sasl->force_ir || data->set.sasl_ir)
+      sctx->result = Curl_auth_create_xoauth_bearer_message(sctx->conn->user,
+                                                      oauth_bearer,
+                                                      &sctx->resp);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static bool sasl_choose_plain(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if(sctx->user && (sctx->enabledmechs & SASL_MECH_PLAIN)) {
+    sctx->mech = SASL_MECH_STRING_PLAIN;
+    sctx->state1 = SASL_PLAIN;
+    sctx->sasl->authused = SASL_MECH_PLAIN;
+
+    if(sctx->sasl->force_ir || data->set.sasl_ir)
+      sctx->result =
+        Curl_auth_create_plain_message(sctx->conn->sasl_authzid,
+                                       sctx->conn->user, sctx->conn->passwd,
+                                       &sctx->resp);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static bool sasl_choose_login(struct Curl_easy *data, struct sasl_ctx *sctx)
+{
+  if(sctx->user && (sctx->enabledmechs & SASL_MECH_LOGIN)) {
+    sctx->mech = SASL_MECH_STRING_LOGIN;
+    sctx->state1 = SASL_LOGIN;
+    sctx->state2 = SASL_LOGIN_PASSWD;
+    sctx->sasl->authused = SASL_MECH_LOGIN;
+
+    if(sctx->sasl->force_ir || data->set.sasl_ir)
+      Curl_auth_create_login_message(sctx->conn->user, &sctx->resp);
+    return TRUE;
+  }
+  return FALSE;
+}
+
 /*
  * Curl_sasl_start()
  *
@@ -342,185 +539,66 @@
 CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
                          bool force_ir, saslprogress *progress)
 {
-  CURLcode result = CURLE_OK;
-  struct connectdata *conn = data->conn;
-  unsigned short enabledmechs;
-  const char *mech = NULL;
-  struct bufref resp;
-  saslstate state1 = SASL_STOP;
-  saslstate state2 = SASL_FINAL;
-  const char *hostname, *disp_hostname;
-  int port;
-#if defined(USE_KERBEROS5) || defined(USE_NTLM)
-  const char *service = data->set.str[STRING_SERVICE_NAME] ?
-    data->set.str[STRING_SERVICE_NAME] :
-    sasl->params->service;
-#endif
-  const char *oauth_bearer = data->set.str[STRING_BEARER];
-  struct bufref nullmsg;
+  struct sasl_ctx sctx;
 
-  Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
-  Curl_bufref_init(&nullmsg);
-  Curl_bufref_init(&resp);
   sasl->force_ir = force_ir;    /* Latch for future use */
   sasl->authused = 0;           /* No mechanism used yet */
-  enabledmechs = sasl->authmechs & sasl->prefmech;
   *progress = SASL_IDLE;
 
+  memset(&sctx, 0, sizeof(sctx));
+  sctx.sasl = sasl;
+  sctx.conn = data->conn;
+  sctx.user = data->state.aptr.user;
+  Curl_bufref_init(&sctx.resp);
+  sctx.enabledmechs = sasl->authmechs & sasl->prefmech;
+  sctx.state1 = SASL_STOP;
+  sctx.state2 = SASL_FINAL;
+
   /* Calculate the supported authentication mechanism, by decreasing order of
      security, as well as the initial response where appropriate */
-  if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
-    mech = SASL_MECH_STRING_EXTERNAL;
-    state1 = SASL_EXTERNAL;
-    sasl->authused = SASL_MECH_EXTERNAL;
-
-    if(force_ir || data->set.sasl_ir)
-      Curl_auth_create_external_message(conn->user, &resp);
-  }
-  else if(data->state.aptr.user) {
+  if(sasl_choose_external(data, &sctx) ||
 #if defined(USE_KERBEROS5)
-    if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
-       Curl_auth_user_contains_domain(conn->user)) {
-      sasl->mutual_auth = FALSE;
-      mech = SASL_MECH_STRING_GSSAPI;
-      state1 = SASL_GSSAPI;
-      state2 = SASL_GSSAPI_TOKEN;
-      sasl->authused = SASL_MECH_GSSAPI;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_gssapi_user_message(data, conn->user,
-                                                      conn->passwd,
-                                                      service,
-                                                      conn->host.name,
-                                                      sasl->mutual_auth,
-                                                      NULL, &conn->krb5,
-                                                      &resp);
-    }
-    else
+     sasl_choose_krb5(data, &sctx) ||
 #endif
 #ifdef USE_GSASL
-    if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
-       Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
-                                    &conn->gsasl)) {
-      mech = SASL_MECH_STRING_SCRAM_SHA_256;
-      sasl->authused = SASL_MECH_SCRAM_SHA_256;
-      state1 = SASL_GSASL;
-      state2 = SASL_GSASL;
-
-      result = Curl_auth_gsasl_start(data, conn->user,
-                                     conn->passwd, &conn->gsasl);
-      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
-        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
-    }
-    else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
-            Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
-                                         &conn->gsasl)) {
-      mech = SASL_MECH_STRING_SCRAM_SHA_1;
-      sasl->authused = SASL_MECH_SCRAM_SHA_1;
-      state1 = SASL_GSASL;
-      state2 = SASL_GSASL;
-
-      result = Curl_auth_gsasl_start(data, conn->user,
-                                     conn->passwd, &conn->gsasl);
-      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
-        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
-    }
-    else
+     sasl_choose_gsasl(data, &sctx) ||
 #endif
 #ifndef CURL_DISABLE_DIGEST_AUTH
-    if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
-       Curl_auth_is_digest_supported()) {
-      mech = SASL_MECH_STRING_DIGEST_MD5;
-      state1 = SASL_DIGESTMD5;
-      sasl->authused = SASL_MECH_DIGEST_MD5;
-    }
-    else if(enabledmechs & SASL_MECH_CRAM_MD5) {
-      mech = SASL_MECH_STRING_CRAM_MD5;
-      state1 = SASL_CRAMMD5;
-      sasl->authused = SASL_MECH_CRAM_MD5;
-    }
-    else
+     sasl_choose_digest(data, &sctx) ||
 #endif
 #ifdef USE_NTLM
-    if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
-      mech = SASL_MECH_STRING_NTLM;
-      state1 = SASL_NTLM;
-      state2 = SASL_NTLM_TYPE2MSG;
-      sasl->authused = SASL_MECH_NTLM;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_ntlm_type1_message(data,
-                                                     conn->user, conn->passwd,
-                                                     service,
-                                                     hostname,
-                                                     &conn->ntlm, &resp);
-      }
-    else
+     sasl_choose_ntlm(data, &sctx) ||
 #endif
-    if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) {
-      mech = SASL_MECH_STRING_OAUTHBEARER;
-      state1 = SASL_OAUTH2;
-      state2 = SASL_OAUTH2_RESP;
-      sasl->authused = SASL_MECH_OAUTHBEARER;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_oauth_bearer_message(conn->user,
-                                                       hostname,
-                                                       port,
-                                                       oauth_bearer,
-                                                       &resp);
-    }
-    else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
-      mech = SASL_MECH_STRING_XOAUTH2;
-      state1 = SASL_OAUTH2;
-      sasl->authused = SASL_MECH_XOAUTH2;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_xoauth_bearer_message(conn->user,
-                                                        oauth_bearer,
-                                                        &resp);
-    }
-    else if(enabledmechs & SASL_MECH_PLAIN) {
-      mech = SASL_MECH_STRING_PLAIN;
-      state1 = SASL_PLAIN;
-      sasl->authused = SASL_MECH_PLAIN;
-
-      if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_plain_message(conn->sasl_authzid,
-                                                conn->user, conn->passwd,
-                                                &resp);
-    }
-    else if(enabledmechs & SASL_MECH_LOGIN) {
-      mech = SASL_MECH_STRING_LOGIN;
-      state1 = SASL_LOGIN;
-      state2 = SASL_LOGIN_PASSWD;
-      sasl->authused = SASL_MECH_LOGIN;
-
-      if(force_ir || data->set.sasl_ir)
-        Curl_auth_create_login_message(conn->user, &resp);
-    }
+     sasl_choose_oauth(data, &sctx) ||
+     sasl_choose_oauth2(data, &sctx) ||
+     sasl_choose_plain(data, &sctx) ||
+     sasl_choose_login(data, &sctx)) {
+    /* selected, either we have a mechanism or a failure */
+    DEBUGASSERT(sctx.mech || sctx.result);
   }
 
-  if(!result && mech) {
-    sasl->curmech = mech;
-    if(Curl_bufref_ptr(&resp))
-      result = build_message(sasl, &resp);
+  if(!sctx.result && sctx.mech) {
+    sasl->curmech = sctx.mech;
+    if(Curl_bufref_ptr(&sctx.resp))
+      sctx.result = build_message(sasl, &sctx.resp);
 
     if(sasl->params->maxirlen &&
-       strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
-      Curl_bufref_free(&resp);
+       strlen(sctx.mech) + Curl_bufref_len(&sctx.resp) >
+         sasl->params->maxirlen)
+      Curl_bufref_free(&sctx.resp);
 
-    if(!result)
-      result = sasl->params->sendauth(data, mech, &resp);
+    if(!sctx.result)
+      sctx.result = sasl->params->sendauth(data, sctx.mech, &sctx.resp);
 
-    if(!result) {
+    if(!sctx.result) {
       *progress = SASL_INPROGRESS;
-      sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
+      sasl_state(sasl, data, Curl_bufref_ptr(&sctx.resp) ?
+                 sctx.state2 : sctx.state1);
     }
   }
 
-  Curl_bufref_free(&resp);
-  return result;
+  Curl_bufref_free(&sctx.resp);
+  return sctx.result;
 }
 
 /*
@@ -535,7 +613,7 @@
   struct connectdata *conn = data->conn;
   saslstate newstate = SASL_FINAL;
   struct bufref resp;
-  const char *hostname, *disp_hostname;
+  const char *hostname;
   int port;
 #if defined(USE_KERBEROS5) || defined(USE_NTLM) \
     || !defined(CURL_DISABLE_DIGEST_AUTH)
@@ -546,7 +624,7 @@
   const char *oauth_bearer = data->set.str[STRING_BEARER];
   struct bufref serverdata;
 
-  Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
+  Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
   Curl_bufref_init(&serverdata);
   Curl_bufref_init(&resp);
   *progress = SASL_INPROGRESS;
@@ -587,8 +665,11 @@
 #ifdef USE_GSASL
   case SASL_GSASL:
     result = get_server_message(sasl, data, &serverdata);
-    if(!result)
-      result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
+    if(!result) {
+      struct gsasldata *gsasl = Curl_auth_gsasl_get(conn);
+      result = !gsasl ? CURLE_OUT_OF_MEMORY :
+        Curl_auth_gsasl_token(data, &serverdata, gsasl, &resp);
+    }
     if(!result && Curl_bufref_len(&resp) > 0)
       newstate = SASL_GSASL;
     break;
@@ -615,50 +696,57 @@
 #endif
 
 #ifdef USE_NTLM
-  case SASL_NTLM:
+  case SASL_NTLM: {
     /* Create the type-1 message */
-    result = Curl_auth_create_ntlm_type1_message(data,
-                                                 conn->user, conn->passwd,
-                                                 service, hostname,
-                                                 &conn->ntlm, &resp);
+    struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
+    result = !ntlm ? CURLE_OUT_OF_MEMORY :
+      Curl_auth_create_ntlm_type1_message(data,
+                                          conn->user, conn->passwd,
+                                          service, hostname,
+                                          ntlm, &resp);
     newstate = SASL_NTLM_TYPE2MSG;
     break;
-  case SASL_NTLM_TYPE2MSG:
+  }
+  case SASL_NTLM_TYPE2MSG: {
     /* Decode the type-2 message */
-    result = get_server_message(sasl, data, &serverdata);
+    struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
+    result = !ntlm ? CURLE_FAILED_INIT :
+      get_server_message(sasl, data, &serverdata);
     if(!result)
-      result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
-                                                   &conn->ntlm);
+      result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm);
     if(!result)
       result = Curl_auth_create_ntlm_type3_message(data, conn->user,
-                                                   conn->passwd, &conn->ntlm,
+                                                   conn->passwd, ntlm,
                                                    &resp);
     break;
+  }
 #endif
 
 #if defined(USE_KERBEROS5)
-  case SASL_GSSAPI:
-    result = Curl_auth_create_gssapi_user_message(data, conn->user,
-                                                  conn->passwd,
-                                                  service,
-                                                  conn->host.name,
+  case SASL_GSSAPI: {
+    struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
+    result = !krb5 ? CURLE_OUT_OF_MEMORY :
+      Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd,
+                                                  service, conn->host.name,
                                                   sasl->mutual_auth, NULL,
-                                                  &conn->krb5,
-                                                  &resp);
+                                                  krb5, &resp);
     newstate = SASL_GSSAPI_TOKEN;
     break;
+  }
   case SASL_GSSAPI_TOKEN:
     result = get_server_message(sasl, data, &serverdata);
     if(!result) {
-      if(sasl->mutual_auth) {
+      struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
+      if(!krb5)
+        result = CURLE_OUT_OF_MEMORY;
+      else if(sasl->mutual_auth) {
         /* Decode the user token challenge and create the optional response
            message */
         result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
                                                       NULL, NULL,
                                                       sasl->mutual_auth,
                                                       &serverdata,
-                                                      &conn->krb5,
-                                                      &resp);
+                                                      krb5, &resp);
         newstate = SASL_GSSAPI_NO_DATA;
       }
       else
@@ -666,19 +754,22 @@
         result = Curl_auth_create_gssapi_security_message(data,
                                                           conn->sasl_authzid,
                                                           &serverdata,
-                                                          &conn->krb5,
-                                                          &resp);
+                                                          krb5, &resp);
     }
     break;
   case SASL_GSSAPI_NO_DATA:
     /* Decode the security challenge and create the response message */
     result = get_server_message(sasl, data, &serverdata);
-    if(!result)
-      result = Curl_auth_create_gssapi_security_message(data,
-                                                        conn->sasl_authzid,
-                                                        &serverdata,
-                                                        &conn->krb5,
-                                                        &resp);
+    if(!result) {
+      struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
+      if(!krb5)
+        result = CURLE_OUT_OF_MEMORY;
+      else
+        result = Curl_auth_create_gssapi_security_message(data,
+                                                          conn->sasl_authzid,
+                                                          &serverdata,
+                                                          krb5, &resp);
+    }
     break;
 #endif
 
diff --git a/Utilities/cmcurl/lib/curl_sasl.h b/Utilities/cmcurl/lib/curl_sasl.h
index 59983f7..0674d56 100644
--- a/Utilities/cmcurl/lib/curl_sasl.h
+++ b/Utilities/cmcurl/lib/curl_sasl.h
@@ -135,10 +135,6 @@
   (wordlen == (sizeof(mech) - 1) / sizeof(char) && \
    !memcmp(line, mech, wordlen))
 
-/* This is used to cleanup any libraries or curl modules used by the sasl
-   functions */
-void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused);
-
 /* Convert a mechanism name to a token */
 unsigned short Curl_sasl_decode_mech(const char *ptr,
                                      size_t maxlen, size_t *len);
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index 2ffebf0..daf80a3 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -228,46 +228,46 @@
 
 #ifdef HTTP_ONLY
 #  ifndef CURL_DISABLE_DICT
-#    define CURL_DISABLE_DICT
+#  define CURL_DISABLE_DICT
 #  endif
 #  ifndef CURL_DISABLE_FILE
-#    define CURL_DISABLE_FILE
+#  define CURL_DISABLE_FILE
 #  endif
 #  ifndef CURL_DISABLE_FTP
-#    define CURL_DISABLE_FTP
+#  define CURL_DISABLE_FTP
 #  endif
 #  ifndef CURL_DISABLE_GOPHER
-#    define CURL_DISABLE_GOPHER
+#  define CURL_DISABLE_GOPHER
 #  endif
 #  ifndef CURL_DISABLE_IMAP
-#    define CURL_DISABLE_IMAP
+#  define CURL_DISABLE_IMAP
 #  endif
 #  ifndef CURL_DISABLE_LDAP
-#    define CURL_DISABLE_LDAP
+#  define CURL_DISABLE_LDAP
 #  endif
 #  ifndef CURL_DISABLE_LDAPS
-#    define CURL_DISABLE_LDAPS
+#  define CURL_DISABLE_LDAPS
 #  endif
 #  ifndef CURL_DISABLE_MQTT
-#    define CURL_DISABLE_MQTT
+#  define CURL_DISABLE_MQTT
 #  endif
 #  ifndef CURL_DISABLE_POP3
-#    define CURL_DISABLE_POP3
+#  define CURL_DISABLE_POP3
 #  endif
 #  ifndef CURL_DISABLE_RTSP
-#    define CURL_DISABLE_RTSP
+#  define CURL_DISABLE_RTSP
 #  endif
 #  ifndef CURL_DISABLE_SMB
-#    define CURL_DISABLE_SMB
+#  define CURL_DISABLE_SMB
 #  endif
 #  ifndef CURL_DISABLE_SMTP
-#    define CURL_DISABLE_SMTP
+#  define CURL_DISABLE_SMTP
 #  endif
 #  ifndef CURL_DISABLE_TELNET
-#    define CURL_DISABLE_TELNET
+#  define CURL_DISABLE_TELNET
 #  endif
 #  ifndef CURL_DISABLE_TFTP
-#    define CURL_DISABLE_TFTP
+#  define CURL_DISABLE_TFTP
 #  endif
 #endif
 
@@ -485,64 +485,48 @@
 # endif
 #endif
 
-/*
- * Large file (>2Gb) support using Win32 functions.
- */
-
-#ifdef USE_WIN32_LARGE_FILES
+#ifdef _WIN32
 #  ifdef HAVE_IO_H
 #  include <io.h>
 #  endif
 #  include <sys/types.h>
 #  include <sys/stat.h>
-#  undef  lseek
-#  define lseek(fdes,offset,whence)  _lseeki64(fdes, offset, whence)
-#  undef  fstat
-#  define fstat(fdes,stp)            _fstati64(fdes, stp)
-#  undef  stat
-#  define stat(fname,stp)            curlx_win32_stat(fname, stp)
-#  define struct_stat                struct _stati64
-#  define LSEEK_ERROR                (__int64)-1
-#  define open                       curlx_win32_open
-#  define fopen(fname,mode)          curlx_win32_fopen(fname, mode)
-   int curlx_win32_open(const char *filename, int oflag, ...);
-   int curlx_win32_stat(const char *path, struct_stat *buffer);
-   FILE *curlx_win32_fopen(const char *filename, const char *mode);
-#endif
-
-#ifdef __DJGPP__
-/* Requires DJGPP 2.04 */
+#  ifdef USE_WIN32_LARGE_FILES
+     /* Large file (>2Gb) support using Win32 functions. */
+#    undef  lseek
+#    define lseek(fdes, offset, whence)  _lseeki64(fdes, offset, whence)
+#    undef  fstat
+#    define fstat(fdes,stp)              _fstati64(fdes, stp)
+#    undef  stat
+#    define struct_stat                  struct _stati64
+#    define LSEEK_ERROR                  (__int64)-1
+#  else
+     /* Small file (<2Gb) support using Win32 functions. */
+#    ifndef UNDER_CE
+#      undef  lseek
+#      define lseek(fdes, offset, whence)  _lseek(fdes, (long)offset, whence)
+#      define fstat(fdes, stp)             _fstat(fdes, stp)
+#      define struct_stat                  struct _stat
+#    endif
+#    define LSEEK_ERROR                  (long)-1
+#  endif
+#  ifndef UNDER_CE
+     int curlx_win32_stat(const char *path, struct_stat *buffer);
+     int curlx_win32_open(const char *filename, int oflag, ...);
+     FILE *curlx_win32_fopen(const char *filename, const char *mode);
+#    define stat(fname, stp)           curlx_win32_stat(fname, stp)
+#    define open                       curlx_win32_open
+#    define CURL_FOPEN(fname, mode)    curlx_win32_fopen(fname, mode)
+#    define fopen(fname, mode)         CURL_FOPEN(fname, mode)
+#  endif
+#elif defined(__DJGPP__)
+   /* Requires DJGPP 2.04 */
 #  include <unistd.h>
 #  undef  lseek
 #  define lseek(fdes,offset,whence)  llseek(fdes, offset, whence)
 #  define LSEEK_ERROR                (offset_t)-1
 #endif
 
-/*
- * Small file (<2Gb) support using Win32 functions.
- */
-
-#if defined(_WIN32) && !defined(USE_WIN32_LARGE_FILES)
-#  ifdef HAVE_IO_H
-#  include <io.h>
-#  endif
-#  include <sys/types.h>
-#  include <sys/stat.h>
-#  ifndef UNDER_CE
-#    undef  lseek
-#    define lseek(fdes,offset,whence)  _lseek(fdes, (long)offset, whence)
-#    define fstat(fdes,stp)            _fstat(fdes, stp)
-#    define stat(fname,stp)            curlx_win32_stat(fname, stp)
-#    define struct_stat                struct _stat
-#    define open                       curlx_win32_open
-#    define fopen(fname,mode)          curlx_win32_fopen(fname, mode)
-     int curlx_win32_stat(const char *path, struct_stat *buffer);
-     int curlx_win32_open(const char *filename, int oflag, ...);
-     FILE *curlx_win32_fopen(const char *filename, const char *mode);
-#  endif
-#  define LSEEK_ERROR                (long)-1
-#endif
-
 #ifndef struct_stat
 #define struct_stat struct stat
 #endif
@@ -597,7 +581,7 @@
 #    endif
 #  endif
 #  ifndef SIZEOF_OFF_T
-#    define SIZEOF_OFF_T 4
+#  define SIZEOF_OFF_T 4
 #  endif
 #endif
 
@@ -605,9 +589,9 @@
 #error "too small curl_off_t"
 #else
    /* assume SIZEOF_CURL_OFF_T == 8 */
-#  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
+#  define CURL_OFF_T_MAX 0x7FFFFFFFFFFFFFFF
 #endif
-#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
+#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - 1)
 
 #if (SIZEOF_CURL_OFF_T != 8)
 #  error "curl_off_t must be exactly 64 bits"
@@ -692,12 +676,8 @@
 #    define select(n,r,w,x,t) select_s(n,r,w,x,t)
 #    define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
 #    include <tcp.h>
-#    ifdef word
-#      undef word
-#    endif
-#    ifdef byte
-#      undef byte
-#    endif
+#    undef word
+#    undef byte
 
 #  endif /* MSDOS */
 
@@ -754,8 +734,8 @@
 #endif
 
 #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
-  defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
-  defined(USE_BEARSSL) || defined(USE_RUSTLS)
+  defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
+  defined(USE_RUSTLS)
 #define USE_SSL    /* SSL support has been enabled */
 #endif
 
@@ -790,7 +770,7 @@
 /* Single point where USE_NTLM definition might be defined */
 #ifndef CURL_DISABLE_NTLM
 #  if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                   \
-  defined(USE_GNUTLS) || defined(USE_SECTRANSP) ||                      \
+  defined(USE_GNUTLS) ||                                                \
   defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
   (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
 #    define USE_CURL_NTLM_CORE
diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h
index c1051e0..bec45de 100644
--- a/Utilities/cmcurl/lib/curl_setup_once.h
+++ b/Utilities/cmcurl/lib/curl_setup_once.h
@@ -41,11 +41,9 @@
 #include <sys/types.h>
 #endif
 
-#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
-#endif
 
-#ifdef HAVE_SYS_TIME_H
+#if !defined(_WIN32) || defined(__MINGW32__)
 #include <sys/time.h>
 #endif
 
@@ -96,7 +94,7 @@
 #  endif
 #endif
 
-#ifdef HAVE_SYS_SOCKET_H
+#ifndef _WIN32
 #include <sys/socket.h>
 #endif
 
@@ -197,17 +195,19 @@
  */
 
 #ifdef HAVE_CLOSESOCKET
-#  define sclose(x)  closesocket((x))
+#  define CURL_SCLOSE(x)  closesocket((x))
 #elif defined(HAVE_CLOSESOCKET_CAMEL)
-#  define sclose(x)  CloseSocket((x))
+#  define CURL_SCLOSE(x)  CloseSocket((x))
 #elif defined(MSDOS)  /* Watt-32 */
-#  define sclose(x)  close_s((x))
+#  define CURL_SCLOSE(x)  close_s((x))
 #elif defined(USE_LWIPSOCK)
-#  define sclose(x)  lwip_close((x))
+#  define CURL_SCLOSE(x)  lwip_close((x))
 #else
-#  define sclose(x)  close((x))
+#  define CURL_SCLOSE(x)  close((x))
 #endif
 
+#define sclose(x)  CURL_SCLOSE(x)
+
 /*
  * Stack-independent version of fcntl() on sockets:
  */
diff --git a/Utilities/cmcurl/lib/curl_sha512_256.c b/Utilities/cmcurl/lib/curl_sha512_256.c
index 2d8a23f..81bfddc 100644
--- a/Utilities/cmcurl/lib/curl_sha512_256.c
+++ b/Utilities/cmcurl/lib/curl_sha512_256.c
@@ -34,9 +34,7 @@
  * * GnuTLS
  * * wolfSSL
  * * Schannel SSPI
- * * Secure Transport (Darwin)
  * * mbedTLS
- * * BearSSL
  * * Rustls
  * Skip the backend if it does not support the required algorithm */
 
diff --git a/Utilities/cmcurl/lib/curl_sspi.c b/Utilities/cmcurl/lib/curl_sspi.c
index cd577e8..5f19e96 100644
--- a/Utilities/cmcurl/lib/curl_sspi.c
+++ b/Utilities/cmcurl/lib/curl_sspi.c
@@ -28,6 +28,7 @@
 
 #include <curl/curl.h>
 #include "curl_sspi.h"
+#include "strdup.h"
 #include "curlx/multibyte.h"
 #include "system_win32.h"
 #include "curlx/version_win32.h"
@@ -37,23 +38,6 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-/* We use our own typedef here since some headers might lack these */
-typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
-
-/* See definition of SECURITY_ENTRYPOINT in sspi.h */
-#ifdef UNICODE
-#  ifdef UNDER_CE
-#    define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
-#  else
-#    define SECURITYENTRYPOINT "InitSecurityInterfaceW"
-#  endif
-#else
-#  define SECURITYENTRYPOINT "InitSecurityInterfaceA"
-#endif
-
-/* Handle of security.dll or secur32.dll, depending on Windows version */
-HMODULE Curl_hSecDll = NULL;
-
 /* Pointer to SSPI dispatch table */
 PSecurityFunctionTable Curl_pSecFn = NULL;
 
@@ -76,31 +60,14 @@
  */
 CURLcode Curl_sspi_global_init(void)
 {
-  INITSECURITYINTERFACE_FN pInitSecurityInterface;
-
   /* If security interface is not yet initialized try to do this */
-  if(!Curl_hSecDll) {
-    /* Security Service Provider Interface (SSPI) functions are located in
-     * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
-     * have both these DLLs (security.dll forwards calls to secur32.dll) */
-
-    /* Load SSPI dll into the address space of the calling process */
-    if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL))
-      Curl_hSecDll = Curl_load_library(TEXT("security.dll"));
-    else
-      Curl_hSecDll = Curl_load_library(TEXT("secur32.dll"));
-    if(!Curl_hSecDll)
-      return CURLE_FAILED_INIT;
-
-    /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
-    pInitSecurityInterface =
-      CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN,
-                          (GetProcAddress(Curl_hSecDll, SECURITYENTRYPOINT)));
-    if(!pInitSecurityInterface)
-      return CURLE_FAILED_INIT;
-
+  if(!Curl_pSecFn) {
     /* Get pointer to Security Service Provider Interface dispatch table */
-    Curl_pSecFn = pInitSecurityInterface();
+#ifdef __MINGW32CE__
+    Curl_pSecFn = InitSecurityInterfaceW();
+#else
+    Curl_pSecFn = InitSecurityInterface();
+#endif
     if(!Curl_pSecFn)
       return CURLE_FAILED_INIT;
   }
@@ -119,9 +86,7 @@
  */
 void Curl_sspi_global_cleanup(void)
 {
-  if(Curl_hSecDll) {
-    FreeLibrary(Curl_hSecDll);
-    Curl_hSecDll = NULL;
+  if(Curl_pSecFn) {
     Curl_pSecFn = NULL;
   }
 }
diff --git a/Utilities/cmcurl/lib/curl_sspi.h b/Utilities/cmcurl/lib/curl_sspi.h
index 8fdf8ef..540cdfd 100644
--- a/Utilities/cmcurl/lib/curl_sspi.h
+++ b/Utilities/cmcurl/lib/curl_sspi.h
@@ -57,7 +57,6 @@
 void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity);
 
 /* Forward-declaration of global variables defined in curl_sspi.c */
-extern HMODULE Curl_hSecDll;
 extern PSecurityFunctionTable Curl_pSecFn;
 
 /* Provide some definitions missing in old headers */
diff --git a/Utilities/cmcurl/lib/curl_trc.c b/Utilities/cmcurl/lib/curl_trc.c
index 566cdc5..334b6e2 100644
--- a/Utilities/cmcurl/lib/curl_trc.c
+++ b/Utilities/cmcurl/lib/curl_trc.c
@@ -31,7 +31,6 @@
 #include "easyif.h"
 #include "cfilters.h"
 #include "multiif.h"
-#include "strcase.h"
 
 #include "cf-socket.h"
 #include "connect.h"
@@ -206,7 +205,7 @@
 static void trc_infof(struct Curl_easy *data,
                       struct curl_trc_feat *feat,
                       const char *opt_id, int opt_id_idx,
-                      const char * const fmt, va_list ap)  CURL_PRINTF(5, 0);
+                      const char * const fmt, va_list ap) CURL_PRINTF(5, 0);
 
 static void trc_infof(struct Curl_easy *data,
                       struct curl_trc_feat *feat,
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.h b/Utilities/cmcurl/lib/curlx/binmode.h
similarity index 67%
rename from Utilities/cmcurl/lib/vtls/sectransp.h
rename to Utilities/cmcurl/lib/curlx/binmode.h
index c82dc18..3f356ed 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.h
+++ b/Utilities/cmcurl/lib/curlx/binmode.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_SECTRANSP_H
-#define HEADER_CURL_SECTRANSP_H
+#ifndef HEADER_CURL_TOOL_BINMODE_H
+#define HEADER_CURL_TOOL_BINMODE_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,7 +7,6 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) Nick Zitzmann, <nickzman@gmail.com>.
  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
@@ -26,9 +25,15 @@
  ***************************************************************************/
 #include "../curl_setup.h"
 
-#ifdef USE_SECTRANSP
+#if (defined(HAVE_SETMODE) || defined(HAVE__SETMODE)) && defined(O_BINARY)
+/* Requires io.h and/or fcntl.h when available */
+#ifdef HAVE__SETMODE
+#  define CURLX_SET_BINMODE(stream)  (void)_setmode(fileno(stream), O_BINARY)
+#else
+#  define CURLX_SET_BINMODE(stream)  (void)setmode(fileno(stream), O_BINARY)
+#endif
+#else
+#  define CURLX_SET_BINMODE(stream)  (void)stream; Curl_nop_stmt
+#endif
 
-extern const struct Curl_ssl Curl_ssl_sectransp;
-
-#endif /* USE_SECTRANSP */
-#endif /* HEADER_CURL_SECTRANSP_H */
+#endif /* HEADER_CURL_TOOL_BINMODE_H */
diff --git a/Utilities/cmcurl/lib/curlx/curlx.h b/Utilities/cmcurl/lib/curlx/curlx.h
index 983c7b5..9f7bd3a 100644
--- a/Utilities/cmcurl/lib/curlx/curlx.h
+++ b/Utilities/cmcurl/lib/curlx/curlx.h
@@ -31,6 +31,9 @@
  * be.
  */
 
+#include "binmode.h"
+/* "binmode.h" provides macro CURLX_SET_BINMODE() */
+
 #include "nonblock.h"
 /* "nonblock.h" provides curlx_nonblock() */
 
@@ -65,10 +68,16 @@
 #include "timeval.h"
 #include "timediff.h"
 
+#include "wait.h"
+/* for curlx_wait_ms */
+
 #include "winapi.h"
 /* for curlx_winapi_strerror */
 
 #include "inet_pton.h"
 /* for curlx_inet_pton */
 
+#include "inet_ntop.h"
+/* for curlx_inet_ntop */
+
 #endif /* HEADER_CURL_CURLX_H */
diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/curlx/inet_ntop.c
similarity index 86%
rename from Utilities/cmcurl/lib/inet_ntop.c
rename to Utilities/cmcurl/lib/curlx/inet_ntop.c
index bb2ec57..e5ff45c 100644
--- a/Utilities/cmcurl/lib/inet_ntop.c
+++ b/Utilities/cmcurl/lib/curlx/inet_ntop.c
@@ -20,7 +20,7 @@
  * Original code by Paul Vixie. "curlified" by Gisle Vanem.
  */
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
 #ifndef HAVE_INET_NTOP
 
@@ -35,7 +35,6 @@
 #endif
 
 #include "inet_ntop.h"
-#include "curl_printf.h"
 
 #define IN6ADDRSZ       16
 /* #define INADDRSZ         4 */
@@ -65,8 +64,9 @@
 
   DEBUGASSERT(size >= 16);
 
-  tmp[0] = '\0';
-  (void)msnprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
+  /* this sprintf() does not overflow the buffer. Avoids snprintf to work more
+     widely. Avoids the msnprintf family to work as a curlx function. */
+  (void)(sprintf)(tmp, "%d.%d.%d.%d",
                   ((int)((unsigned char)src[0])) & 0xff,
                   ((int)((unsigned char)src[1])) & 0xff,
                   ((int)((unsigned char)src[2])) & 0xff,
@@ -162,7 +162,21 @@
       tp += strlen(tp);
       break;
     }
-    tp += msnprintf(tp, 5, "%x", words[i]);
+    else {
+      /* Lower-case digits. Can't use the set from mprintf.c since this
+         needs to work as a curlx function */
+      static const unsigned char ldigits[] = "0123456789abcdef";
+
+      unsigned int w = words[i];
+      /* output lowercase 16bit hex number but ignore leading zeroes */
+      if(w & 0xf000)
+        *tp++ = ldigits[(w & 0xf000) >> 12];
+      if(w & 0xff00)
+        *tp++ = ldigits[(w & 0x0f00) >> 8];
+      if(w & 0xfff0)
+        *tp++ = ldigits[(w & 0x00f0) >> 4];
+      *tp++ = ldigits[(w & 0x000f)];
+    }
   }
 
   /* Was it a trailing run of 0x00's?
@@ -196,7 +210,7 @@
  * code. This is to avoid losing the actual last Winsock error. When this
  * function returns NULL, check errno not SOCKERRNO.
  */
-char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
+char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size)
 {
   switch(af) {
   case AF_INET:
diff --git a/Utilities/cmcurl/lib/inet_ntop.h b/Utilities/cmcurl/lib/curlx/inet_ntop.h
similarity index 86%
rename from Utilities/cmcurl/lib/inet_ntop.h
rename to Utilities/cmcurl/lib/curlx/inet_ntop.h
index 9923daa..68f8c8d 100644
--- a/Utilities/cmcurl/lib/inet_ntop.h
+++ b/Utilities/cmcurl/lib/curlx/inet_ntop.h
@@ -24,26 +24,26 @@
  *
  ***************************************************************************/
 
-#include "curl_setup.h"
+#include "../curl_setup.h"
 
-char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+char *curlx_inet_ntop(int af, const void *addr, char *buf, size_t size);
 
 #ifdef HAVE_INET_NTOP
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
-#ifdef HAVE_SYS_SOCKET_H
+#ifndef _WIN32
 #include <sys/socket.h>
 #endif
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
 #ifdef __AMIGA__
-#define Curl_inet_ntop(af,addr,buf,size)                                \
+#define curlx_inet_ntop(af,addr,buf,size)                               \
   (char *)inet_ntop(af, CURL_UNCONST(addr), (unsigned char *)buf,       \
                     (curl_socklen_t)(size))
 #else
-#define Curl_inet_ntop(af,addr,buf,size)                \
+#define curlx_inet_ntop(af,addr,buf,size)                \
   inet_ntop(af, addr, buf, (curl_socklen_t)(size))
 #endif
 #endif
diff --git a/Utilities/cmcurl/lib/curlx/inet_pton.h b/Utilities/cmcurl/lib/curlx/inet_pton.h
index a9dc430..610b329 100644
--- a/Utilities/cmcurl/lib/curlx/inet_pton.h
+++ b/Utilities/cmcurl/lib/curlx/inet_pton.h
@@ -32,7 +32,7 @@
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
-#ifdef HAVE_SYS_SOCKET_H
+#ifndef _WIN32
 #include <sys/socket.h>
 #endif
 #ifdef HAVE_ARPA_INET_H
diff --git a/Utilities/cmcurl/lib/curlx/strparse.c b/Utilities/cmcurl/lib/curlx/strparse.c
index b8b2a14..ecdf5b9 100644
--- a/Utilities/cmcurl/lib/curlx/strparse.c
+++ b/Utilities/cmcurl/lib/curlx/strparse.c
@@ -23,7 +23,10 @@
  ***************************************************************************/
 
 #include "strparse.h"
-#include "../strcase.h"
+
+#ifndef WITHOUT_LIBCURL
+#include <curl/curl.h>  /* for curl_strnequal() */
+#endif
 
 void curlx_str_init(struct Curl_str *out)
 {
@@ -40,7 +43,7 @@
 /* Get a word until the first DELIM or end of string. At least one byte long.
    return non-zero on error */
 int curlx_str_until(const char **linep, struct Curl_str *out,
-                   const size_t max, char delim)
+                    const size_t max, char delim)
 {
   const char *s = *linep;
   size_t len = 0;
@@ -64,7 +67,7 @@
 /* Get a word until the first space or end of string. At least one byte long.
    return non-zero on error */
 int curlx_str_word(const char **linep, struct Curl_str *out,
-                  const size_t max)
+                   const size_t max)
 {
   return curlx_str_until(linep, out, max, ' ');
 }
@@ -72,7 +75,7 @@
 /* Get a word until a newline byte or end of string. At least one byte long.
    return non-zero on error */
 int curlx_str_untilnl(const char **linep, struct Curl_str *out,
-                     const size_t max)
+                      const size_t max)
 {
   const char *s = *linep;
   size_t len = 0;
@@ -96,7 +99,7 @@
 /* Get a "quoted" word. No escaping possible.
    return non-zero on error */
 int curlx_str_quotedword(const char **linep, struct Curl_str *out,
-                        const size_t max)
+                         const size_t max)
 {
   const char *s = *linep;
   size_t len = 0;
@@ -238,7 +241,7 @@
 int curlx_str_casecompare(struct Curl_str *str, const char *check)
 {
   size_t clen = check ? strlen(check) : 0;
-  return ((str->len == clen) && strncasecompare(str->str, check, clen));
+  return ((str->len == clen) && curl_strnequal(str->str, check, clen));
 }
 #endif
 
diff --git a/Utilities/cmcurl/lib/curlx/strparse.h b/Utilities/cmcurl/lib/curlx/strparse.h
index 17bfdb8..6a0bf28 100644
--- a/Utilities/cmcurl/lib/curlx/strparse.h
+++ b/Utilities/cmcurl/lib/curlx/strparse.h
@@ -55,17 +55,17 @@
 /* Get a word until the first DELIM or end of string
    return non-zero on error */
 int curlx_str_until(const char **linep, struct Curl_str *out, const size_t max,
-                   char delim);
+                    char delim);
 
 /* Get a word until a newline byte or end of string. At least one byte long.
    return non-zero on error */
 int curlx_str_untilnl(const char **linep, struct Curl_str *out,
-                     const size_t max);
+                      const size_t max);
 
 /* Get a "quoted" word. No escaping possible.
    return non-zero on error */
 int curlx_str_quotedword(const char **linep, struct Curl_str *out,
-                        const size_t max);
+                         const size_t max);
 
 /* Advance over a single character.
    return non-zero on error */
diff --git a/Utilities/cmcurl/lib/curlx/wait.c b/Utilities/cmcurl/lib/curlx/wait.c
new file mode 100644
index 0000000..f568fb6
--- /dev/null
+++ b/Utilities/cmcurl/lib/curlx/wait.c
@@ -0,0 +1,97 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "../curl_setup.h"
+
+#ifndef HAVE_SELECT
+#error "We cannot compile without select() support."
+#endif
+
+#include <limits.h>
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#elif defined(HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#ifdef MSDOS
+#include <dos.h>  /* delay() */
+#endif
+
+#include "timediff.h"
+#include "wait.h"
+
+/*
+ * Internal function used for waiting a specific amount of ms in
+ * Curl_socket_check() and Curl_poll() when no file descriptor is provided to
+ * wait on, just being used to delay execution. Winsock select() and poll()
+ * timeout mechanisms need a valid socket descriptor in a not null file
+ * descriptor set to work. Waiting indefinitely with this function is not
+ * allowed, a zero or negative timeout value will return immediately. Timeout
+ * resolution, accuracy, as well as maximum supported value is system
+ * dependent, neither factor is a critical issue for the intended use of this
+ * function in the library.
+ *
+ * Return values:
+ *   -1 = system call error, or invalid timeout value
+ *    0 = specified timeout has elapsed, or interrupted
+ */
+int curlx_wait_ms(timediff_t timeout_ms)
+{
+  int r = 0;
+
+  if(!timeout_ms)
+    return 0;
+  if(timeout_ms < 0) {
+    SET_SOCKERRNO(SOCKEINVAL);
+    return -1;
+  }
+#if defined(MSDOS)
+  delay((unsigned int)timeout_ms);
+#elif defined(_WIN32)
+  /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
+#if TIMEDIFF_T_MAX >= ULONG_MAX
+  if(timeout_ms >= ULONG_MAX)
+    timeout_ms = ULONG_MAX-1;
+    /* do not use ULONG_MAX, because that is equal to INFINITE */
+#endif
+  Sleep((DWORD)timeout_ms);
+#else
+  /* avoid using poll() for this since it behaves incorrectly with no sockets
+     on Apple operating systems */
+  {
+    struct timeval pending_tv;
+    r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
+  }
+#endif /* _WIN32 */
+  if(r) {
+    if((r == -1) && (SOCKERRNO == SOCKEINTR))
+      /* make EINTR from select or poll not a "lethal" error */
+      r = 0;
+    else
+      r = -1;
+  }
+  return r;
+}
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.h b/Utilities/cmcurl/lib/curlx/wait.h
similarity index 80%
rename from Utilities/cmcurl/lib/vtls/bearssl.h
rename to Utilities/cmcurl/lib/curlx/wait.h
index 8bb254f..208bc20 100644
--- a/Utilities/cmcurl/lib/vtls/bearssl.h
+++ b/Utilities/cmcurl/lib/curlx/wait.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_BEARSSL_H
-#define HEADER_CURL_BEARSSL_H
+#ifndef HEADER_CURL_WAIT_H
+#define HEADER_CURL_WAIT_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) Michael Forney, <mforney@mforney.org>
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,9 +26,6 @@
 
 #include "../curl_setup.h"
 
-#ifdef USE_BEARSSL
+int curlx_wait_ms(timediff_t timeout_ms);
 
-extern const struct Curl_ssl Curl_ssl_bearssl;
-
-#endif /* USE_BEARSSL */
-#endif /* HEADER_CURL_BEARSSL_H */
+#endif /* HEADER_CURL_WAIT_H */
diff --git a/Utilities/cmcurl/lib/curlx/warnless.c b/Utilities/cmcurl/lib/curlx/warnless.c
index 5ca9245..c6cb7c6 100644
--- a/Utilities/cmcurl/lib/curlx/warnless.c
+++ b/Utilities/cmcurl/lib/curlx/warnless.c
@@ -35,11 +35,6 @@
 
 #endif /* __INTEL_COMPILER && __unix__ */
 
-#ifdef _WIN32
-#undef read
-#undef write
-#endif
-
 #include <limits.h>
 
 #define CURL_MASK_UCHAR   ((unsigned char)~0)
@@ -295,21 +290,3 @@
 #  pragma warning(pop)
 #endif
 }
-
-#ifdef _WIN32
-
-ssize_t curlx_read(int fd, void *buf, size_t count)
-{
-  return (ssize_t)read(fd, buf, curlx_uztoui(count));
-}
-
-ssize_t curlx_write(int fd, const void *buf, size_t count)
-{
-  return (ssize_t)write(fd, buf, curlx_uztoui(count));
-}
-
-#endif /* _WIN32 */
-
-/* Ensure that warnless.h redefinitions continue to have an effect
-   in "unity" builds. */
-#undef HEADER_CURL_WARNLESS_H_REDEFS
diff --git a/Utilities/cmcurl/lib/curlx/warnless.h b/Utilities/cmcurl/lib/curlx/warnless.h
index c78b611..0a0c608 100644
--- a/Utilities/cmcurl/lib/curlx/warnless.h
+++ b/Utilities/cmcurl/lib/curlx/warnless.h
@@ -58,23 +58,10 @@
 size_t curlx_sitouz(int sinum);
 
 #ifdef _WIN32
-
-ssize_t curlx_read(int fd, void *buf, size_t count);
-
-ssize_t curlx_write(int fd, const void *buf, size_t count);
-
-#endif /* _WIN32 */
-
-#endif /* HEADER_CURL_WARNLESS_H */
-
-#ifndef HEADER_CURL_WARNLESS_H_REDEFS
-#define HEADER_CURL_WARNLESS_H_REDEFS
-
-#ifdef _WIN32
 #undef  read
-#define read(fd, buf, count)  curlx_read(fd, buf, count)
+#define read(fd, buf, count)  (ssize_t)_read(fd, buf, curlx_uztoui(count))
 #undef  write
-#define write(fd, buf, count) curlx_write(fd, buf, count)
+#define write(fd, buf, count) (ssize_t)_write(fd, buf, curlx_uztoui(count))
 #endif
 
-#endif /* HEADER_CURL_WARNLESS_H_REDEFS */
+#endif /* HEADER_CURL_WARNLESS_H */
diff --git a/Utilities/cmcurl/lib/cw-out.c b/Utilities/cmcurl/lib/cw-out.c
index 097ef85..ee7dc65 100644
--- a/Utilities/cmcurl/lib/cw-out.c
+++ b/Utilities/cmcurl/lib/cw-out.c
@@ -31,6 +31,7 @@
 #include "headers.h"
 #include "multiif.h"
 #include "sendf.h"
+#include "transfer.h"
 #include "cw-out.h"
 #include "cw-pause.h"
 
@@ -234,11 +235,9 @@
         failf(data, "Write callback asked for PAUSE when not supported");
         return CURLE_WRITE_ERROR;
       }
-      /* mark the connection as RECV paused */
-      data->req.keepon |= KEEP_RECV_PAUSE;
       ctx->paused = TRUE;
       CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
-      break;
+      return Curl_xfer_pause_recv(data, TRUE);
     }
     else if(CURL_WRITEFUNC_ERROR == nwritten) {
       failf(data, "client returned ERROR on write of %zu bytes", wlen);
diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c
index 637f349..7f13e6f 100644
--- a/Utilities/cmcurl/lib/dict.c
+++ b/Utilities/cmcurl/lib/dict.c
@@ -60,7 +60,6 @@
 #include "progress.h"
 #include "dict.h"
 #include "curl_printf.h"
-#include "strcase.h"
 #include "curl_memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -198,9 +197,9 @@
   if(result)
     return result;
 
-  if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
-     strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
-     strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
+  if(curl_strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
+     curl_strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
+     curl_strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
 
     word = strchr(path, ':');
     if(word) {
@@ -245,9 +244,9 @@
     }
     Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */
   }
-  else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
-          strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
-          strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
+  else if(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
+          curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
+          curl_strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
 
     word = strchr(path, ':');
     if(word) {
diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c
index 9f40840..f96ae08 100644
--- a/Utilities/cmcurl/lib/doh.c
+++ b/Utilities/cmcurl/lib/doh.c
@@ -257,7 +257,7 @@
 
     if(!dohp->pending) {
       /* DoH completed, run the transfer picking up the results */
-      Curl_expire(data, 0, EXPIRE_RUN_NOW);
+      Curl_multi_mark_dirty(data);
     }
   }
 }
@@ -377,8 +377,6 @@
      options should be added to check doh proxy insecure separately,
      CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
      */
-  if(data->set.ssl.falsestart)
-    ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
   if(data->set.str[STRING_SSL_CAFILE]) {
     ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
                        data->set.str[STRING_SSL_CAFILE]);
@@ -590,7 +588,7 @@
 }
 
 static void doh_store_aaaa(const unsigned char *doh, int index,
-                              struct dohentry *d)
+                           struct dohentry *d)
 {
   /* silently ignore addresses over the limit */
   if(d->numaddr < DOH_MAX_ADDR) {
diff --git a/Utilities/cmcurl/lib/dynhds.c b/Utilities/cmcurl/lib/dynhds.c
index 5c52d74..dcb9193 100644
--- a/Utilities/cmcurl/lib/dynhds.c
+++ b/Utilities/cmcurl/lib/dynhds.c
@@ -150,7 +150,7 @@
   size_t i;
   for(i = 0; i < dynhds->hds_len; ++i) {
     if(dynhds->hds[i]->namelen == namelen &&
-       strncasecompare(dynhds->hds[i]->name, name, namelen)) {
+       curl_strnequal(dynhds->hds[i]->name, name, namelen)) {
       return dynhds->hds[i];
     }
   }
@@ -297,7 +297,7 @@
     size_t i;
     for(i = 0; i < dynhds->hds_len; ++i) {
       if((namelen == dynhds->hds[i]->namelen) &&
-         strncasecompare(name, dynhds->hds[i]->name, namelen))
+         curl_strnequal(name, dynhds->hds[i]->name, namelen))
         ++n;
     }
   }
@@ -325,7 +325,7 @@
     size_t i, len;
     for(i = 0; i < dynhds->hds_len; ++i) {
       if((namelen == dynhds->hds[i]->namelen) &&
-         strncasecompare(name, dynhds->hds[i]->name, namelen)) {
+         curl_strnequal(name, dynhds->hds[i]->name, namelen)) {
         ++n;
         --dynhds->hds_len;
         dynhds->strs_len -= (dynhds->hds[i]->namelen +
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index 3f86786..9c1f1c6 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/easy.c
@@ -67,6 +67,7 @@
 #include "amigaos.h"
 #include "macos.h"
 #include "curlx/warnless.h"
+#include "curlx/wait.h"
 #include "sigpipe.h"
 #include "vssh/ssh.h"
 #include "setopt.h"
@@ -128,9 +129,6 @@
 curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
 curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
 curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
-#if defined(_WIN32) && defined(UNICODE)
-curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup;
-#endif
 
 #if defined(_MSC_VER) && defined(_DLL)
 #  pragma warning(pop)
@@ -156,9 +154,6 @@
     Curl_crealloc = (curl_realloc_callback)realloc;
     Curl_cstrdup = (curl_strdup_callback)system_strdup;
     Curl_ccalloc = (curl_calloc_callback)calloc;
-#if defined(_WIN32) && defined(UNICODE)
-    Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
-#endif
   }
 
   if(Curl_trc_init()) {
@@ -611,7 +606,7 @@
 #endif
       pollrc = 0;
       if(ev->ms > 0)
-        Curl_wait_ms(ev->ms);
+        curlx_wait_ms(ev->ms);
     }
 
     ev->msbump = FALSE; /* reset here */
@@ -733,7 +728,7 @@
 
 
 /*
- * easy_perform() is the external interface that performs a blocking
+ * easy_perform() is the internal interface that performs a blocking
  * transfer as previously setup.
  *
  * CONCEPT: This function creates a multi handle, adds the easy handle to it,
@@ -1128,13 +1123,12 @@
  */
 CURLcode curl_easy_pause(CURL *d, int action)
 {
-  struct SingleRequest *k;
   CURLcode result = CURLE_OK;
-  int oldstate;
-  int newstate;
   bool recursive = FALSE;
-  bool keep_changed, unpause_read, not_all_paused;
+  bool changed = FALSE;
   struct Curl_easy *data = d;
+  bool recv_paused, recv_paused_new;
+  bool send_paused, send_paused_new;
 
   if(!GOOD_EASY_HANDLE(data) || !data->conn)
     /* crazy input, do not continue */
@@ -1142,62 +1136,37 @@
 
   if(Curl_is_in_callback(data))
     recursive = TRUE;
-  k = &data->req;
-  oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
 
-  /* first switch off both pause bits then set the new pause bits */
-  newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) |
-    ((action & CURLPAUSE_RECV) ? KEEP_RECV_PAUSE : 0) |
-    ((action & CURLPAUSE_SEND) ? KEEP_SEND_PAUSE : 0);
+  recv_paused = Curl_xfer_recv_is_paused(data);
+  recv_paused_new = (action & CURLPAUSE_RECV);
+  send_paused = Curl_xfer_send_is_paused(data);
+  send_paused_new = (action & CURLPAUSE_SEND);
 
-  keep_changed = ((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) != oldstate);
-  not_all_paused = (newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
-                   (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE);
-  unpause_read = ((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
-                  (data->mstate == MSTATE_PERFORMING ||
-                   data->mstate == MSTATE_RATELIMITING));
-  /* Unpausing writes is detected on the next run in
-   * transfer.c:Curl_sendrecv(). This is because this may result
-   * in a transfer error if the application's callbacks fail */
+  if(send_paused != send_paused_new) {
+    changed = TRUE;
+    result = Curl_1st_err(result, Curl_xfer_pause_send(data, send_paused_new));
+  }
 
-  /* Set the new keepon state, so it takes effect no matter what error
-   * may happen afterwards. */
-  k->keepon = newstate;
+  if(recv_paused != recv_paused_new) {
+    changed = TRUE;
+    result = Curl_1st_err(result, Curl_xfer_pause_recv(data, recv_paused_new));
+  }
 
   /* If not completely pausing both directions now, run again in any case. */
-  if(not_all_paused) {
+  if(!Curl_xfer_is_blocked(data)) {
     Curl_expire(data, 0, EXPIRE_RUN_NOW);
     /* reset the too-slow time keeper */
     data->state.keeps_speed.tv_sec = 0;
-    /* Simulate socket events on next run for unpaused directions */
-    if(!(newstate & KEEP_SEND_PAUSE))
-      data->state.select_bits |= CURL_CSELECT_OUT;
-    if(!(newstate & KEEP_RECV_PAUSE))
-      data->state.select_bits |= CURL_CSELECT_IN;
     /* On changes, tell application to update its timers. */
-    if(keep_changed && data->multi) {
-      if(Curl_update_timer(data->multi)) {
+    if(changed && data->multi) {
+      if(Curl_update_timer(data->multi) && !result)
         result = CURLE_ABORTED_BY_CALLBACK;
-        goto out;
-      }
     }
   }
 
-  if(unpause_read) {
-    result = Curl_creader_unpause(data);
-    if(result)
-      goto out;
-  }
-
-  if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
-    Curl_conn_ev_data_pause(data, FALSE);
-    result = Curl_cwriter_unpause(data);
-  }
-
-out:
-  if(!result && !data->state.done && keep_changed && data->multi)
+  if(!result && changed && !data->state.done && data->multi)
     /* pause/unpausing may result in multi event changes */
-    if(Curl_multi_ev_assess_xfer(data->multi, data))
+    if(Curl_multi_ev_assess_xfer(data->multi, data) && !result)
       result = CURLE_ABORTED_BY_CALLBACK;
 
   if(recursive)
@@ -1241,7 +1210,6 @@
 CURLcode curl_easy_recv(CURL *d, void *buffer, size_t buflen, size_t *n)
 {
   CURLcode result;
-  ssize_t n1;
   struct connectdata *c;
   struct Curl_easy *data = d;
 
@@ -1258,13 +1226,7 @@
     Curl_attach_connection(data, c);
 
   *n = 0;
-  result = Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, &n1);
-
-  if(result)
-    return result;
-
-  *n = (size_t)n1;
-  return CURLE_OK;
+  return Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, n);
 }
 
 #ifndef CURL_DISABLE_WEBSOCKETS
diff --git a/Utilities/cmcurl/lib/easygetopt.c b/Utilities/cmcurl/lib/easygetopt.c
index 5d30d39..0113121 100644
--- a/Utilities/cmcurl/lib/easygetopt.c
+++ b/Utilities/cmcurl/lib/easygetopt.c
@@ -1,9 +1,9 @@
 /***************************************************************************
  *                                  _   _ ____  _
- *  Project                     ___| | | |  _ | |
+ *  Project                     ___| | | |  _ \| |
  *                             / __| | | | |_) | |
  *                            | (__| |_| |  _ <| |___
- *                             ___|___/|_| ______|
+ *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
  *
@@ -23,7 +23,6 @@
  ***************************************************************************/
 
 #include "curl_setup.h"
-#include "strcase.h"
 #include "easyoptions.h"
 
 #ifndef CURL_DISABLE_GETOPTIONS
@@ -37,7 +36,7 @@
     const struct curl_easyoption *o = &Curl_easyopts[0];
     do {
       if(name) {
-        if(strcasecompare(o->name, name))
+        if(curl_strequal(o->name, name))
           return o;
       }
       else {
diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c
index 3cd906d..a292ba3 100644
--- a/Utilities/cmcurl/lib/escape.c
+++ b/Utilities/cmcurl/lib/escape.c
@@ -85,7 +85,7 @@
     else {
       /* encode it */
       unsigned char out[3]={'%'};
-      Curl_hexbyte(&out[1], in, FALSE);
+      Curl_hexbyte(&out[1], in);
       if(curlx_dyn_addn(&d, out, 3))
         return NULL;
     }
@@ -212,7 +212,8 @@
   DEBUGASSERT(src && len && (olen >= 3));
   if(src && len && (olen >= 3)) {
     while(len-- && (olen >= 3)) {
-      Curl_hexbyte(out, *src, TRUE);
+      out[0] = Curl_ldigits[*src >> 4];
+      out[1] = Curl_ldigits[*src & 0x0F];
       ++src;
       out += 2;
       olen -= 2;
@@ -225,14 +226,11 @@
 
 /* Curl_hexbyte
  *
- * Output a single unsigned char as a two-digit hex number, lowercase or
- * uppercase
+ * Output a single unsigned char as a two-digit UPPERCASE hex number.
  */
 void Curl_hexbyte(unsigned char *dest, /* must fit two bytes */
-                  unsigned char val,
-                  bool lowercase)
+                  unsigned char val)
 {
-  const unsigned char *t = lowercase ? Curl_ldigits : Curl_udigits;
-  dest[0] = t[val >> 4];
-  dest[1] = t[val & 0x0F];
+  dest[0] = Curl_udigits[val >> 4];
+  dest[1] = Curl_udigits[val & 0x0F];
 }
diff --git a/Utilities/cmcurl/lib/escape.h b/Utilities/cmcurl/lib/escape.h
index 1f2bac8..a43fc38 100644
--- a/Utilities/cmcurl/lib/escape.h
+++ b/Utilities/cmcurl/lib/escape.h
@@ -42,7 +42,6 @@
                     unsigned char *out, size_t olen); /* output buffer size */
 
 void Curl_hexbyte(unsigned char *dest, /* must fit two bytes */
-                  unsigned char val,
-                  bool lowercase);
+                  unsigned char val);
 
 #endif /* HEADER_CURL_ESCAPE_H */
diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c
index 2aa8eee..5a4b52e 100644
--- a/Utilities/cmcurl/lib/formdata.c
+++ b/Utilities/cmcurl/lib/formdata.c
@@ -34,7 +34,6 @@
 #include "urldata.h" /* for struct Curl_easy */
 #include "mime.h"
 #include "vtls/vtls.h"
-#include "strcase.h"
 #include "sendf.h"
 #include "strdup.h"
 #include "rand.h"
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index 2db4a7d..59a4dfe 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -60,7 +60,7 @@
 #include "cf-socket.h"
 #include "connect.h"
 #include "strerror.h"
-#include "inet_ntop.h"
+#include "curlx/inet_ntop.h"
 #include "curlx/inet_pton.h"
 #include "select.h"
 #include "parsedate.h" /* for the week day and month names */
@@ -114,12 +114,14 @@
   "QUOTE",
   "RETR_PREQUOTE",
   "STOR_PREQUOTE",
+  "LIST_PREQUOTE",
   "POSTQUOTE",
   "CWD",
   "MKD",
   "MDTM",
   "TYPE",
   "LIST_TYPE",
+  "RETR_LIST_TYPE",
   "RETR_TYPE",
   "STOR_TYPE",
   "SIZE",
@@ -765,7 +767,12 @@
 static CURLcode ftp_state_pwd(struct Curl_easy *data,
                               struct ftp_conn *ftpc)
 {
-  CURLcode result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PWD");
+  CURLcode result;
+#ifdef DEBUGBUILD
+  if(!data->id && getenv("CURL_FTP_PWD_STOP"))
+    return CURLE_OK;
+#endif
+  result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PWD");
   if(!result)
     ftp_state(data, ftpc, FTP_PWD);
 
@@ -978,6 +985,12 @@
       port_min = port_max = 0;
 
     if(addrlen) {
+      const struct Curl_sockaddr_ex *remote_addr =
+       Curl_conn_get_remote_addr(data, FIRSTSOCKET);
+
+      DEBUGASSERT(remote_addr);
+      if(!remote_addr)
+        goto out;
       DEBUGASSERT(addr);
       if(addrlen >= sizeof(ipstr))
         goto out;
@@ -985,9 +998,9 @@
       ipstr[addrlen] = 0;
 
       /* attempt to get the address of the given interface name */
-      switch(Curl_if2ip(conn->remote_addr->family,
+      switch(Curl_if2ip(remote_addr->family,
 #ifdef USE_IPV6
-                        Curl_ipv6_scope(&conn->remote_addr->curl_sa_addr),
+                        Curl_ipv6_scope(&remote_addr->curl_sa_addr),
                         conn->scope_id,
 #endif
                         ipstr, hbuf, sizeof(hbuf))) {
@@ -1020,11 +1033,11 @@
     switch(sa->sa_family) {
 #ifdef USE_IPV6
     case AF_INET6:
-      r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
+      r = curlx_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
       break;
 #endif
     default:
-      r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
+      r = curlx_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
       break;
     }
     if(!r) {
@@ -1052,7 +1065,8 @@
   /* step 2, create a socket for the requested address */
   error = 0;
   for(ai = res; ai; ai = ai->ai_next) {
-    if(Curl_socket_open(data, ai, NULL, conn->transport, &portsock)) {
+    if(Curl_socket_open(data, ai, NULL,
+                        Curl_conn_get_transport(data, conn), &portsock)) {
       error = SOCKERRNO;
       continue;
     }
@@ -1245,7 +1259,7 @@
     }
     data->conn->bits.do_more = FALSE;
     Curl_pgrsTime(data, TIMER_STARTACCEPT);
-    Curl_expire(data, data->set.accepttimeout ?
+    Curl_expire(data, (data->set.accepttimeout > 0) ?
                 data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT,
                 EXPIRE_FTP_ACCEPT);
   }
@@ -1448,6 +1462,14 @@
   return result;
 }
 
+static CURLcode ftp_state_list_prequote(struct Curl_easy *data,
+                                        struct ftp_conn *ftpc,
+                                        struct FTP *ftp)
+{
+  /* We have sent the TYPE, now we must send the list of prequote strings */
+  return ftp_state_quote(data, ftpc, ftp, TRUE, FTP_LIST_PREQUOTE);
+}
+
 static CURLcode ftp_state_retr_prequote(struct Curl_easy *data,
                                         struct ftp_conn *ftpc,
                                         struct FTP *ftp)
@@ -1636,6 +1658,7 @@
     break;
   case FTP_RETR_PREQUOTE:
   case FTP_STOR_PREQUOTE:
+  case FTP_LIST_PREQUOTE:
     item = data->set.prequote;
     break;
   case FTP_POSTQUOTE:
@@ -1725,6 +1748,10 @@
       break;
     case FTP_POSTQUOTE:
       break;
+    case FTP_LIST_PREQUOTE:
+      ftp_state(data, ftpc, FTP_LIST_TYPE);
+      result = ftp_state_list(data, ftpc, ftp);
+      break;
     }
   }
 
@@ -2198,6 +2225,8 @@
     result = ftp_state_retr_prequote(data, ftpc, ftp);
   else if(instate == FTP_STOR_TYPE)
     result = ftp_state_stor_prequote(data, ftpc, ftp);
+  else if(instate == FTP_RETR_LIST_TYPE)
+    result = ftp_state_list_prequote(data, ftpc, ftp);
 
   return result;
 }
@@ -2961,7 +2990,7 @@
           return CURLE_OUT_OF_MEMORY;
 
         /* Check for special servers here. */
-        if(strcasecompare(os, "OS/400")) {
+        if(curl_strequal(os, "OS/400")) {
           /* Force OS400 name format 1. */
           result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
           if(result) {
@@ -3002,6 +3031,7 @@
     case FTP_POSTQUOTE:
     case FTP_RETR_PREQUOTE:
     case FTP_STOR_PREQUOTE:
+    case FTP_LIST_PREQUOTE:
       if((ftpcode >= 400) && !ftpc->count2) {
         /* failure response code, and not allowed to fail */
         failf(data, "QUOT command failed with %03d", ftpcode);
@@ -3071,6 +3101,7 @@
     case FTP_LIST_TYPE:
     case FTP_RETR_TYPE:
     case FTP_STOR_TYPE:
+    case FTP_RETR_LIST_TYPE:
       result = ftp_state_type_resp(data, ftpc, ftp, ftpcode, ftpc->state);
       break;
 
@@ -3125,8 +3156,8 @@
 
 /* called repeatedly until done from multi.c */
 static CURLcode ftp_statemach(struct Curl_easy *data,
-                               struct ftp_conn *ftpc,
-                               bool *done)
+                              struct ftp_conn *ftpc,
+                              bool *done)
 {
   CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE);
 
@@ -3675,7 +3706,8 @@
 
       if(result)
         ;
-      else if(data->state.list_only || !ftpc->file) {
+      else if((data->state.list_only || !ftpc->file) &&
+              !(data->set.prequote)) {
         /* The specified path ends with a slash, and therefore we think this
            is a directory that is requested, use LIST. But before that we
            need to set ASCII transfer mode. */
@@ -3689,8 +3721,14 @@
         /* otherwise just fall through */
       }
       else {
-        result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii,
-                             FTP_RETR_TYPE);
+        if(data->set.prequote && !ftpc->file) {
+          result = ftp_nb_type(data, ftpc, ftp, TRUE,
+                               FTP_RETR_LIST_TYPE);
+        }
+        else {
+          result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii,
+                               FTP_RETR_TYPE);
+        }
         if(result)
           return result;
       }
@@ -4118,7 +4156,7 @@
      will try to send the QUIT command, otherwise it will just return.
   */
   ftpc->shutdown = TRUE;
-  if(dead_connection)
+  if(dead_connection || Curl_pp_needs_flush(data, &ftpc->pp))
     ftpc->ctl_valid = FALSE;
 
   /* The FTP session may or may not have been allocated/setup at this point! */
diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h
index c31aa93..5266198 100644
--- a/Utilities/cmcurl/lib/ftp.h
+++ b/Utilities/cmcurl/lib/ftp.h
@@ -62,12 +62,14 @@
   FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
   FTP_RETR_PREQUOTE,
   FTP_STOR_PREQUOTE,
+  FTP_LIST_PREQUOTE,
   FTP_POSTQUOTE,
   FTP_CWD,  /* change dir */
   FTP_MKD,  /* if the dir did not exist */
   FTP_MDTM, /* to figure out the datestamp */
   FTP_TYPE, /* to set type when doing a head-like request */
   FTP_LIST_TYPE, /* set type when about to do a dir list */
+  FTP_RETR_LIST_TYPE,
   FTP_RETR_TYPE, /* set type when about to RETR a file */
   FTP_STOR_TYPE, /* set type when about to STOR a file */
   FTP_SIZE, /* get the remote file's size for head-like request */
diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c
index 70939d6..360f7ae 100644
--- a/Utilities/cmcurl/lib/ftplistparser.c
+++ b/Utilities/cmcurl/lib/ftplistparser.c
@@ -396,407 +396,500 @@
   return CURLE_OK;
 }
 
+static CURLcode parse_unix_totalsize(struct ftp_parselist_data *parser,
+                                     struct fileinfo *infop,
+                                     const char c)
+{
+  size_t len = curlx_dyn_len(&infop->buf);
+  char *mem = curlx_dyn_ptr(&infop->buf);
+  switch(parser->state.UNIX.sub.total_dirsize) {
+  case PL_UNIX_TOTALSIZE_INIT:
+    if(c == 't') {
+      parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
+      parser->item_length++;
+    }
+    else {
+      parser->state.UNIX.main = PL_UNIX_FILETYPE;
+      /* continue to fall through */
+    }
+    break;
+  case PL_UNIX_TOTALSIZE_READING:
+    parser->item_length++;
+    if(c == '\r') {
+      parser->item_length--;
+      if(len)
+        curlx_dyn_setlen(&infop->buf, --len);
+    }
+    else if(c == '\n') {
+      mem[parser->item_length - 1] = 0;
+      if(!strncmp("total ", mem, 6)) {
+        const char *endptr = mem + 6;
+        /* here we can deal with directory size, pass the leading
+           whitespace and then the digits */
+        curlx_str_passblanks(&endptr);
+        while(ISDIGIT(*endptr))
+          endptr++;
+        if(*endptr) {
+          return CURLE_FTP_BAD_FILE_LIST;
+        }
+        parser->state.UNIX.main = PL_UNIX_FILETYPE;
+        curlx_dyn_reset(&infop->buf);
+      }
+      else
+        return CURLE_FTP_BAD_FILE_LIST;
+
+    }
+    break;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode parse_unix_permission(struct ftp_parselist_data *parser,
+                                      struct fileinfo *infop,
+                                      const char c)
+{
+  char *mem = curlx_dyn_ptr(&infop->buf);
+  parser->item_length++;
+  if((parser->item_length <= 9) && !strchr("rwx-tTsS", c))
+    return CURLE_FTP_BAD_FILE_LIST;
+
+  else if(parser->item_length == 10) {
+    unsigned int perm;
+    if(c != ' ')
+      return CURLE_FTP_BAD_FILE_LIST;
+
+    mem[10] = 0; /* terminate permissions */
+    perm = ftp_pl_get_permission(mem + parser->item_offset);
+    if(perm & FTP_LP_MALFORMATED_PERM)
+      return CURLE_FTP_BAD_FILE_LIST;
+
+    parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
+    parser->file_data->info.perm = perm;
+    parser->offsets.perm = parser->item_offset;
+
+    parser->item_length = 0;
+    parser->state.UNIX.main = PL_UNIX_HLINKS;
+    parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode parse_unix_hlinks(struct ftp_parselist_data *parser,
+                                  struct fileinfo *infop,
+                                  const char c)
+{
+  size_t len = curlx_dyn_len(&infop->buf);
+  char *mem = curlx_dyn_ptr(&infop->buf);
+
+  switch(parser->state.UNIX.sub.hlinks) {
+  case PL_UNIX_HLINKS_PRESPACE:
+    if(c != ' ') {
+      if(ISDIGIT(c) && len) {
+        parser->item_offset = len - 1;
+        parser->item_length = 1;
+        parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
+      }
+      else
+        return CURLE_FTP_BAD_FILE_LIST;
+    }
+    break;
+  case PL_UNIX_HLINKS_NUMBER:
+    parser->item_length ++;
+    if(c == ' ') {
+      const char *p = &mem[parser->item_offset];
+      curl_off_t hlinks;
+      mem[parser->item_offset + parser->item_length - 1] = 0;
+
+      if(!curlx_str_number(&p, &hlinks, LONG_MAX)) {
+        parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
+        parser->file_data->info.hardlinks = (long)hlinks;
+      }
+      parser->item_length = 0;
+      parser->item_offset = 0;
+      parser->state.UNIX.main = PL_UNIX_USER;
+      parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
+    }
+    else if(!ISDIGIT(c))
+      return CURLE_FTP_BAD_FILE_LIST;
+
+    break;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode parse_unix_user(struct ftp_parselist_data *parser,
+                                struct fileinfo *infop,
+                                const char c)
+{
+  size_t len = curlx_dyn_len(&infop->buf);
+  char *mem = curlx_dyn_ptr(&infop->buf);
+  switch(parser->state.UNIX.sub.user) {
+  case PL_UNIX_USER_PRESPACE:
+    if(c != ' ' && len) {
+      parser->item_offset = len - 1;
+      parser->item_length = 1;
+      parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
+    }
+    break;
+  case PL_UNIX_USER_PARSING:
+    parser->item_length++;
+    if(c == ' ') {
+      mem[parser->item_offset + parser->item_length - 1] = 0;
+      parser->offsets.user = parser->item_offset;
+      parser->state.UNIX.main = PL_UNIX_GROUP;
+      parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
+      parser->item_offset = 0;
+      parser->item_length = 0;
+    }
+    break;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode parse_unix_group(struct ftp_parselist_data *parser,
+                                 struct fileinfo *infop,
+                                 const char c)
+{
+  size_t len = curlx_dyn_len(&infop->buf);
+  char *mem = curlx_dyn_ptr(&infop->buf);
+  switch(parser->state.UNIX.sub.group) {
+  case PL_UNIX_GROUP_PRESPACE:
+    if(c != ' ' && len) {
+      parser->item_offset = len - 1;
+      parser->item_length = 1;
+      parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
+    }
+    break;
+  case PL_UNIX_GROUP_NAME:
+    parser->item_length++;
+    if(c == ' ') {
+      mem[parser->item_offset + parser->item_length - 1] = 0;
+      parser->offsets.group = parser->item_offset;
+      parser->state.UNIX.main = PL_UNIX_SIZE;
+      parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
+      parser->item_offset = 0;
+      parser->item_length = 0;
+    }
+    break;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode parse_unix_size(struct ftp_parselist_data *parser,
+                                struct fileinfo *infop,
+                                const char c)
+{
+  size_t len = curlx_dyn_len(&infop->buf);
+  char *mem = curlx_dyn_ptr(&infop->buf);
+  switch(parser->state.UNIX.sub.size) {
+  case PL_UNIX_SIZE_PRESPACE:
+    if(c != ' ') {
+      if(ISDIGIT(c) && len) {
+        parser->item_offset = len - 1;
+        parser->item_length = 1;
+        parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
+      }
+      else
+        return CURLE_FTP_BAD_FILE_LIST;
+    }
+    break;
+  case PL_UNIX_SIZE_NUMBER:
+    parser->item_length++;
+    if(c == ' ') {
+      const char *p = mem + parser->item_offset;
+      curl_off_t fsize;
+      mem[parser->item_offset + parser->item_length - 1] = 0;
+      if(!curlx_str_numblanks(&p, &fsize)) {
+        if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) {
+          parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
+          parser->file_data->info.size = fsize;
+        }
+        parser->item_length = 0;
+        parser->item_offset = 0;
+        parser->state.UNIX.main = PL_UNIX_TIME;
+        parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
+      }
+    }
+    else if(!ISDIGIT(c))
+      return CURLE_FTP_BAD_FILE_LIST;
+
+    break;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode parse_unix_time(struct ftp_parselist_data *parser,
+                                struct fileinfo *infop,
+                                const char c)
+{
+  size_t len = curlx_dyn_len(&infop->buf);
+  char *mem = curlx_dyn_ptr(&infop->buf);
+  struct curl_fileinfo *finfo = &infop->info;
+
+  switch(parser->state.UNIX.sub.time) {
+  case PL_UNIX_TIME_PREPART1:
+    if(c != ' ') {
+      if(ISALNUM(c) && len) {
+        parser->item_offset = len -1;
+        parser->item_length = 1;
+        parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
+      }
+      else
+        return CURLE_FTP_BAD_FILE_LIST;
+    }
+    break;
+  case PL_UNIX_TIME_PART1:
+    parser->item_length++;
+    if(c == ' ')
+      parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
+
+    else if(!ISALNUM(c) && c != '.')
+      return CURLE_FTP_BAD_FILE_LIST;
+
+    break;
+  case PL_UNIX_TIME_PREPART2:
+    parser->item_length++;
+    if(c != ' ') {
+      if(ISALNUM(c))
+        parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
+      else
+        return CURLE_FTP_BAD_FILE_LIST;
+    }
+    break;
+  case PL_UNIX_TIME_PART2:
+    parser->item_length++;
+    if(c == ' ')
+      parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
+    else if(!ISALNUM(c) && c != '.')
+      return CURLE_FTP_BAD_FILE_LIST;
+    break;
+  case PL_UNIX_TIME_PREPART3:
+    parser->item_length++;
+    if(c != ' ') {
+      if(ISALNUM(c))
+        parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
+      else
+        return CURLE_FTP_BAD_FILE_LIST;
+    }
+    break;
+  case PL_UNIX_TIME_PART3:
+    parser->item_length++;
+    if(c == ' ') {
+      mem[parser->item_offset + parser->item_length -1] = 0;
+      parser->offsets.time = parser->item_offset;
+      if(finfo->filetype == CURLFILETYPE_SYMLINK) {
+        parser->state.UNIX.main = PL_UNIX_SYMLINK;
+        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
+      }
+      else {
+        parser->state.UNIX.main = PL_UNIX_FILENAME;
+        parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
+      }
+    }
+    else if(!ISALNUM(c) && c != '.' && c != ':')
+      return CURLE_FTP_BAD_FILE_LIST;
+    break;
+  }
+  return CURLE_OK;
+}
+
+static CURLcode parse_unix_filename(struct Curl_easy *data,
+                                    struct ftp_parselist_data *parser,
+                                    struct fileinfo *infop,
+                                    const char c)
+{
+  size_t len = curlx_dyn_len(&infop->buf);
+  char *mem = curlx_dyn_ptr(&infop->buf);
+  CURLcode result = CURLE_OK;
+
+  switch(parser->state.UNIX.sub.filename) {
+  case PL_UNIX_FILENAME_PRESPACE:
+    if(c != ' ' && len) {
+      parser->item_offset = len - 1;
+      parser->item_length = 1;
+      parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
+    }
+    break;
+  case PL_UNIX_FILENAME_NAME:
+    parser->item_length++;
+    if(c == '\r')
+      parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
+
+    else if(c == '\n') {
+      mem[parser->item_offset + parser->item_length - 1] = 0;
+      parser->offsets.filename = parser->item_offset;
+      parser->state.UNIX.main = PL_UNIX_FILETYPE;
+      result = ftp_pl_insert_finfo(data, infop);
+    }
+    break;
+  case PL_UNIX_FILENAME_WINDOWSEOL:
+    if(c == '\n') {
+      mem[parser->item_offset + parser->item_length - 1] = 0;
+      parser->offsets.filename = parser->item_offset;
+      parser->state.UNIX.main = PL_UNIX_FILETYPE;
+      result = ftp_pl_insert_finfo(data, infop);
+    }
+    else
+      result = CURLE_FTP_BAD_FILE_LIST;
+    break;
+  }
+  return result;
+}
+
+static CURLcode parse_unix_symlink(struct Curl_easy *data,
+                                   struct ftp_parselist_data *parser,
+                                   struct fileinfo *infop,
+                                   const char c)
+{
+  size_t len = curlx_dyn_len(&infop->buf);
+  char *mem = curlx_dyn_ptr(&infop->buf);
+  CURLcode result = CURLE_OK;
+
+  switch(parser->state.UNIX.sub.symlink) {
+  case PL_UNIX_SYMLINK_PRESPACE:
+    if(c != ' ' && len) {
+      parser->item_offset = len - 1;
+      parser->item_length = 1;
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+    }
+    break;
+  case PL_UNIX_SYMLINK_NAME:
+    parser->item_length++;
+    if(c == ' ')
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
+
+    else if(c == '\r' || c == '\n')
+      return CURLE_FTP_BAD_FILE_LIST;
+
+    break;
+  case PL_UNIX_SYMLINK_PRETARGET1:
+    parser->item_length++;
+    if(c == '-')
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
+
+    else if(c == '\r' || c == '\n')
+      return CURLE_FTP_BAD_FILE_LIST;
+    else
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+    break;
+  case PL_UNIX_SYMLINK_PRETARGET2:
+    parser->item_length++;
+    if(c == '>')
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
+    else if(c == '\r' || c == '\n')
+      return CURLE_FTP_BAD_FILE_LIST;
+    else
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+
+    break;
+  case PL_UNIX_SYMLINK_PRETARGET3:
+    parser->item_length++;
+    if(c == ' ') {
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
+      /* now place where is symlink following */
+      mem[parser->item_offset + parser->item_length - 4] = 0;
+      parser->offsets.filename = parser->item_offset;
+      parser->item_length = 0;
+      parser->item_offset = 0;
+    }
+    else if(c == '\r' || c == '\n')
+      return CURLE_FTP_BAD_FILE_LIST;
+    else
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+    break;
+  case PL_UNIX_SYMLINK_PRETARGET4:
+    if(c != '\r' && c != '\n' && len) {
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
+      parser->item_offset = len - 1;
+      parser->item_length = 1;
+    }
+    else
+      return CURLE_FTP_BAD_FILE_LIST;
+
+    break;
+  case PL_UNIX_SYMLINK_TARGET:
+    parser->item_length++;
+    if(c == '\r')
+      parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
+
+    else if(c == '\n') {
+      mem[parser->item_offset + parser->item_length - 1] = 0;
+      parser->offsets.symlink_target = parser->item_offset;
+      result = ftp_pl_insert_finfo(data, infop);
+      if(result)
+        break;
+
+      parser->state.UNIX.main = PL_UNIX_FILETYPE;
+    }
+    break;
+  case PL_UNIX_SYMLINK_WINDOWSEOL:
+    if(c == '\n') {
+      mem[parser->item_offset + parser->item_length - 1] = 0;
+      parser->offsets.symlink_target = parser->item_offset;
+      result = ftp_pl_insert_finfo(data, infop);
+      if(result)
+        break;
+
+      parser->state.UNIX.main = PL_UNIX_FILETYPE;
+    }
+    else
+      result = CURLE_FTP_BAD_FILE_LIST;
+
+    break;
+  }
+  return result;
+}
+
 static CURLcode parse_unix(struct Curl_easy *data,
                            struct ftp_parselist_data *parser,
                            struct fileinfo *infop,
                            const char c)
 {
   struct curl_fileinfo *finfo = &infop->info;
-  size_t len = curlx_dyn_len(&infop->buf);
-  char *mem = curlx_dyn_ptr(&infop->buf);
   CURLcode result = CURLE_OK;
 
   switch(parser->state.UNIX.main) {
   case PL_UNIX_TOTALSIZE:
-    switch(parser->state.UNIX.sub.total_dirsize) {
-    case PL_UNIX_TOTALSIZE_INIT:
-      if(c == 't') {
-        parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
-        parser->item_length++;
-      }
-      else {
-        parser->state.UNIX.main = PL_UNIX_FILETYPE;
-        /* continue to fall through */
-      }
+    result = parse_unix_totalsize(parser, infop, c);
+    if(result)
       break;
-    case PL_UNIX_TOTALSIZE_READING:
-      parser->item_length++;
-      if(c == '\r') {
-        parser->item_length--;
-        if(len)
-          curlx_dyn_setlen(&infop->buf, --len);
-      }
-      else if(c == '\n') {
-        mem[parser->item_length - 1] = 0;
-        if(!strncmp("total ", mem, 6)) {
-          const char *endptr = mem + 6;
-          /* here we can deal with directory size, pass the leading
-             whitespace and then the digits */
-          curlx_str_passblanks(&endptr);
-          while(ISDIGIT(*endptr))
-            endptr++;
-          if(*endptr) {
-            return CURLE_FTP_BAD_FILE_LIST;
-          }
-          parser->state.UNIX.main = PL_UNIX_FILETYPE;
-          curlx_dyn_reset(&infop->buf);
-        }
-        else
-          return CURLE_FTP_BAD_FILE_LIST;
-
-      }
-      break;
-    }
     if(parser->state.UNIX.main != PL_UNIX_FILETYPE)
       break;
     FALLTHROUGH();
   case PL_UNIX_FILETYPE:
     result = unix_filetype(c, &finfo->filetype);
-    if(result)
-      return result;
-    parser->state.UNIX.main = PL_UNIX_PERMISSION;
-    parser->item_length = 0;
-    parser->item_offset = 1;
+    if(!result) {
+      parser->state.UNIX.main = PL_UNIX_PERMISSION;
+      parser->item_length = 0;
+      parser->item_offset = 1;
+    }
     break;
   case PL_UNIX_PERMISSION:
-    parser->item_length++;
-    if((parser->item_length <= 9) && !strchr("rwx-tTsS", c))
-      return CURLE_FTP_BAD_FILE_LIST;
-
-    else if(parser->item_length == 10) {
-      unsigned int perm;
-      if(c != ' ')
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      mem[10] = 0; /* terminate permissions */
-      perm = ftp_pl_get_permission(mem + parser->item_offset);
-      if(perm & FTP_LP_MALFORMATED_PERM)
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
-      parser->file_data->info.perm = perm;
-      parser->offsets.perm = parser->item_offset;
-
-      parser->item_length = 0;
-      parser->state.UNIX.main = PL_UNIX_HLINKS;
-      parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
-    }
+    result = parse_unix_permission(parser, infop, c);
     break;
   case PL_UNIX_HLINKS:
-    switch(parser->state.UNIX.sub.hlinks) {
-    case PL_UNIX_HLINKS_PRESPACE:
-      if(c != ' ') {
-        if(ISDIGIT(c) && len) {
-          parser->item_offset = len - 1;
-          parser->item_length = 1;
-          parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
-        }
-        else
-          return CURLE_FTP_BAD_FILE_LIST;
-      }
-      break;
-    case PL_UNIX_HLINKS_NUMBER:
-      parser->item_length ++;
-      if(c == ' ') {
-        const char *p = &mem[parser->item_offset];
-        curl_off_t hlinks;
-        mem[parser->item_offset + parser->item_length - 1] = 0;
-
-        if(!curlx_str_number(&p, &hlinks, LONG_MAX)) {
-          parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
-          parser->file_data->info.hardlinks = (long)hlinks;
-        }
-        parser->item_length = 0;
-        parser->item_offset = 0;
-        parser->state.UNIX.main = PL_UNIX_USER;
-        parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
-      }
-      else if(!ISDIGIT(c))
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      break;
-    }
+    result = parse_unix_hlinks(parser, infop, c);
     break;
   case PL_UNIX_USER:
-    switch(parser->state.UNIX.sub.user) {
-    case PL_UNIX_USER_PRESPACE:
-      if(c != ' ' && len) {
-        parser->item_offset = len - 1;
-        parser->item_length = 1;
-        parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
-      }
-      break;
-    case PL_UNIX_USER_PARSING:
-      parser->item_length++;
-      if(c == ' ') {
-        mem[parser->item_offset + parser->item_length - 1] = 0;
-        parser->offsets.user = parser->item_offset;
-        parser->state.UNIX.main = PL_UNIX_GROUP;
-        parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
-        parser->item_offset = 0;
-        parser->item_length = 0;
-      }
-      break;
-    }
+    result = parse_unix_user(parser, infop, c);
     break;
   case PL_UNIX_GROUP:
-    switch(parser->state.UNIX.sub.group) {
-    case PL_UNIX_GROUP_PRESPACE:
-      if(c != ' ' && len) {
-        parser->item_offset = len - 1;
-        parser->item_length = 1;
-        parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
-      }
-      break;
-    case PL_UNIX_GROUP_NAME:
-      parser->item_length++;
-      if(c == ' ') {
-        mem[parser->item_offset + parser->item_length - 1] = 0;
-        parser->offsets.group = parser->item_offset;
-        parser->state.UNIX.main = PL_UNIX_SIZE;
-        parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
-        parser->item_offset = 0;
-        parser->item_length = 0;
-      }
-      break;
-    }
+    result = parse_unix_group(parser, infop, c);
     break;
   case PL_UNIX_SIZE:
-    switch(parser->state.UNIX.sub.size) {
-    case PL_UNIX_SIZE_PRESPACE:
-      if(c != ' ') {
-        if(ISDIGIT(c) && len) {
-          parser->item_offset = len - 1;
-          parser->item_length = 1;
-          parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
-        }
-        else
-          return CURLE_FTP_BAD_FILE_LIST;
-      }
-      break;
-    case PL_UNIX_SIZE_NUMBER:
-      parser->item_length++;
-      if(c == ' ') {
-        const char *p = mem + parser->item_offset;
-        curl_off_t fsize;
-        mem[parser->item_offset + parser->item_length - 1] = 0;
-        if(!curlx_str_numblanks(&p, &fsize)) {
-          if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) {
-            parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
-            parser->file_data->info.size = fsize;
-          }
-          parser->item_length = 0;
-          parser->item_offset = 0;
-          parser->state.UNIX.main = PL_UNIX_TIME;
-          parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
-        }
-      }
-      else if(!ISDIGIT(c))
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      break;
-    }
+    result = parse_unix_size(parser, infop, c);
     break;
   case PL_UNIX_TIME:
-    switch(parser->state.UNIX.sub.time) {
-    case PL_UNIX_TIME_PREPART1:
-      if(c != ' ') {
-        if(ISALNUM(c) && len) {
-          parser->item_offset = len -1;
-          parser->item_length = 1;
-          parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
-        }
-        else
-          return CURLE_FTP_BAD_FILE_LIST;
-      }
-      break;
-    case PL_UNIX_TIME_PART1:
-      parser->item_length++;
-      if(c == ' ')
-        parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
-
-      else if(!ISALNUM(c) && c != '.')
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      break;
-    case PL_UNIX_TIME_PREPART2:
-      parser->item_length++;
-      if(c != ' ') {
-        if(ISALNUM(c))
-          parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
-        else
-          return CURLE_FTP_BAD_FILE_LIST;
-      }
-      break;
-    case PL_UNIX_TIME_PART2:
-      parser->item_length++;
-      if(c == ' ')
-        parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
-      else if(!ISALNUM(c) && c != '.')
-        return CURLE_FTP_BAD_FILE_LIST;
-      break;
-    case PL_UNIX_TIME_PREPART3:
-      parser->item_length++;
-      if(c != ' ') {
-        if(ISALNUM(c))
-          parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
-        else
-          return CURLE_FTP_BAD_FILE_LIST;
-      }
-      break;
-    case PL_UNIX_TIME_PART3:
-      parser->item_length++;
-      if(c == ' ') {
-        mem[parser->item_offset + parser->item_length -1] = 0;
-        parser->offsets.time = parser->item_offset;
-        if(finfo->filetype == CURLFILETYPE_SYMLINK) {
-          parser->state.UNIX.main = PL_UNIX_SYMLINK;
-          parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
-        }
-        else {
-          parser->state.UNIX.main = PL_UNIX_FILENAME;
-          parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
-        }
-      }
-      else if(!ISALNUM(c) && c != '.' && c != ':')
-        return CURLE_FTP_BAD_FILE_LIST;
-      break;
-    }
+    result = parse_unix_time(parser, infop, c);
     break;
   case PL_UNIX_FILENAME:
-    switch(parser->state.UNIX.sub.filename) {
-    case PL_UNIX_FILENAME_PRESPACE:
-      if(c != ' ' && len) {
-        parser->item_offset = len - 1;
-        parser->item_length = 1;
-        parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
-      }
-      break;
-    case PL_UNIX_FILENAME_NAME:
-      parser->item_length++;
-      if(c == '\r')
-        parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
-
-      else if(c == '\n') {
-        mem[parser->item_offset + parser->item_length - 1] = 0;
-        parser->offsets.filename = parser->item_offset;
-        parser->state.UNIX.main = PL_UNIX_FILETYPE;
-        result = ftp_pl_insert_finfo(data, infop);
-        if(result)
-          return result;
-      }
-      break;
-    case PL_UNIX_FILENAME_WINDOWSEOL:
-      if(c == '\n') {
-        mem[parser->item_offset + parser->item_length - 1] = 0;
-        parser->offsets.filename = parser->item_offset;
-        parser->state.UNIX.main = PL_UNIX_FILETYPE;
-        result = ftp_pl_insert_finfo(data, infop);
-        if(result)
-          return result;
-      }
-      else
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      break;
-    }
+    result = parse_unix_filename(data, parser, infop, c);
     break;
   case PL_UNIX_SYMLINK:
-    switch(parser->state.UNIX.sub.symlink) {
-    case PL_UNIX_SYMLINK_PRESPACE:
-      if(c != ' ' && len) {
-        parser->item_offset = len - 1;
-        parser->item_length = 1;
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
-      }
-      break;
-    case PL_UNIX_SYMLINK_NAME:
-      parser->item_length++;
-      if(c == ' ')
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
-
-      else if(c == '\r' || c == '\n')
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      break;
-    case PL_UNIX_SYMLINK_PRETARGET1:
-      parser->item_length++;
-      if(c == '-')
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
-
-      else if(c == '\r' || c == '\n')
-        return CURLE_FTP_BAD_FILE_LIST;
-      else
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
-      break;
-    case PL_UNIX_SYMLINK_PRETARGET2:
-      parser->item_length++;
-      if(c == '>')
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
-      else if(c == '\r' || c == '\n')
-        return CURLE_FTP_BAD_FILE_LIST;
-      else
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
-
-      break;
-    case PL_UNIX_SYMLINK_PRETARGET3:
-      parser->item_length++;
-      if(c == ' ') {
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
-        /* now place where is symlink following */
-        mem[parser->item_offset + parser->item_length - 4] = 0;
-        parser->offsets.filename = parser->item_offset;
-        parser->item_length = 0;
-        parser->item_offset = 0;
-      }
-      else if(c == '\r' || c == '\n')
-        return CURLE_FTP_BAD_FILE_LIST;
-      else
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
-      break;
-    case PL_UNIX_SYMLINK_PRETARGET4:
-      if(c != '\r' && c != '\n' && len) {
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
-        parser->item_offset = len - 1;
-        parser->item_length = 1;
-      }
-      else
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      break;
-    case PL_UNIX_SYMLINK_TARGET:
-      parser->item_length++;
-      if(c == '\r')
-        parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
-
-      else if(c == '\n') {
-        mem[parser->item_offset + parser->item_length - 1] = 0;
-        parser->offsets.symlink_target = parser->item_offset;
-        result = ftp_pl_insert_finfo(data, infop);
-        if(result)
-          return result;
-
-        parser->state.UNIX.main = PL_UNIX_FILETYPE;
-      }
-      break;
-    case PL_UNIX_SYMLINK_WINDOWSEOL:
-      if(c == '\n') {
-        mem[parser->item_offset + parser->item_length - 1] = 0;
-        parser->offsets.symlink_target = parser->item_offset;
-        result = ftp_pl_insert_finfo(data, infop);
-        if(result)
-          return result;
-
-        parser->state.UNIX.main = PL_UNIX_FILETYPE;
-      }
-      else
-        return CURLE_FTP_BAD_FILE_LIST;
-
-      break;
-    }
+    result = parse_unix_symlink(data, parser, infop, c);
     break;
   }
-  return CURLE_OK;
+  return result;
 }
 
 static CURLcode parse_winnt(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c
index 388646b..7ff78d2 100644
--- a/Utilities/cmcurl/lib/getinfo.c
+++ b/Utilities/cmcurl/lib/getinfo.c
@@ -28,6 +28,7 @@
 
 #include "urldata.h"
 #include "getinfo.h"
+#include "cfilters.h"
 #include "vtls/vtls.h"
 #include "connect.h" /* Curl_getconnectinfo() */
 #include "progress.h"
@@ -579,19 +580,14 @@
       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
                                           param_slistp;
       struct curl_tlssessioninfo *tsi = &data->tsi;
-#ifdef USE_SSL
-      struct connectdata *conn = data->conn;
-#endif
 
+      /* we are exposing a pointer to internal memory with unknown
+       * lifetime here. */
       *tsip = tsi;
-      tsi->backend = Curl_ssl_backend();
-      tsi->internals = NULL;
-
-#ifdef USE_SSL
-      if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
-        tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
+      if(!Curl_conn_get_ssl_info(data, data->conn, FIRSTSOCKET, tsi)) {
+        tsi->backend = Curl_ssl_backend();
+        tsi->internals = NULL;
       }
-#endif
     }
     break;
   default:
diff --git a/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c
index 8d13aae..89f47ed 100644
--- a/Utilities/cmcurl/lib/hash.c
+++ b/Utilities/cmcurl/lib/hash.c
@@ -353,7 +353,7 @@
 }
 
 size_t curlx_str_key_compare(void *k1, size_t key1_len,
-                            void *k2, size_t key2_len)
+                             void *k2, size_t key2_len)
 {
   if((key1_len == key2_len) && !memcmp(k1, k2, key1_len))
     return 1;
diff --git a/Utilities/cmcurl/lib/hash.h b/Utilities/cmcurl/lib/hash.h
index 314b811..fcd92db 100644
--- a/Utilities/cmcurl/lib/hash.h
+++ b/Utilities/cmcurl/lib/hash.h
@@ -99,7 +99,7 @@
                                     int (*comp)(void *, void *));
 size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num);
 size_t curlx_str_key_compare(void *k1, size_t key1_len, void *k2,
-                            size_t key2_len);
+                             size_t key2_len);
 void Curl_hash_start_iterate(struct Curl_hash *hash,
                              struct Curl_hash_iterator *iter);
 struct Curl_hash_element *
diff --git a/Utilities/cmcurl/lib/headers.c b/Utilities/cmcurl/lib/headers.c
index 71592a9..426d0e5 100644
--- a/Utilities/cmcurl/lib/headers.c
+++ b/Utilities/cmcurl/lib/headers.c
@@ -26,7 +26,6 @@
 
 #include "urldata.h"
 #include "strdup.h"
-#include "strcase.h"
 #include "sendf.h"
 #include "headers.h"
 #include "curlx/strparse.h"
@@ -88,7 +87,7 @@
   /* we need a first round to count amount of this header */
   for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
     hs = Curl_node_elem(e);
-    if(strcasecompare(hs->name, name) &&
+    if(curl_strequal(hs->name, name) &&
        (hs->type & type) &&
        (hs->request == request)) {
       amount++;
@@ -107,7 +106,7 @@
   else {
     for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
       hs = Curl_node_elem(e);
-      if(strcasecompare(hs->name, name) &&
+      if(curl_strequal(hs->name, name) &&
          (hs->type & type) &&
          (hs->request == request) &&
          (match++ == nameindex)) {
@@ -173,7 +172,7 @@
      the index for the currently selected entry */
   for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
     struct Curl_header_store *check = Curl_node_elem(e);
-    if(strcasecompare(hs->name, check->name) &&
+    if(curl_strequal(hs->name, check->name) &&
        (check->request == request) &&
        (check->type & type))
       amount++;
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index ca6724e..191aaeb 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -54,7 +54,7 @@
 #include "rand.h"
 #include "share.h"
 #include "url.h"
-#include "inet_ntop.h"
+#include "curlx/inet_ntop.h"
 #include "curlx/inet_pton.h"
 #include "multiif.h"
 #include "doh.h"
@@ -145,14 +145,14 @@
   case AF_INET: {
     const struct sockaddr_in *sa4 = (const void *)ai->ai_addr;
     const struct in_addr *ipaddr4 = &sa4->sin_addr;
-    (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
+    (void)curlx_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
     break;
   }
 #ifdef USE_IPV6
   case AF_INET6: {
     const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr;
     const struct in6_addr *ipaddr6 = &sa6->sin6_addr;
-    (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
+    (void)curlx_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
     break;
   }
 #endif
@@ -505,6 +505,8 @@
       return NULL;
     }
   }
+#else
+  (void)data;
 #endif
   if(!hostlen)
     hostlen = strlen(hostname);
@@ -730,7 +732,7 @@
 {
   if(plen > flen)
     return FALSE;
-  return strncasecompare(part, &full[flen - plen], plen);
+  return curl_strnequal(part, &full[flen - plen], plen);
 }
 
 static struct Curl_addrinfo *
@@ -872,8 +874,8 @@
     goto error;
 
   if(!is_ipaddr &&
-     (strcasecompare(hostname, "localhost") ||
-      strcasecompare(hostname, "localhost.") ||
+     (curl_strequal(hostname, "localhost") ||
+      curl_strequal(hostname, "localhost.") ||
       tailmatch(hostname, hostname_len, STRCONST(".localhost")) ||
       tailmatch(hostname, hostname_len, STRCONST(".localhost.")))) {
     addr = get_localhost(port, hostname);
diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c
index 35cc2d7..ce7f505 100644
--- a/Utilities/cmcurl/lib/hostip6.c
+++ b/Utilities/cmcurl/lib/hostip6.c
@@ -44,6 +44,7 @@
 #endif
 
 #include "urldata.h"
+#include "cfilters.h"
 #include "sendf.h"
 #include "hostip.h"
 #include "hash.h"
@@ -104,7 +105,8 @@
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+  hints.ai_socktype =
+    (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
     SOCK_STREAM : SOCK_DGRAM;
 
 #ifndef USE_RESOLVE_ON_IPS
diff --git a/Utilities/cmcurl/lib/hsts.c b/Utilities/cmcurl/lib/hsts.c
index 62a3f89..91f3227 100644
--- a/Utilities/cmcurl/lib/hsts.c
+++ b/Utilities/cmcurl/lib/hsts.c
@@ -33,7 +33,6 @@
 #include "llist.h"
 #include "hsts.h"
 #include "curl_get_line.h"
-#include "strcase.h"
 #include "sendf.h"
 #include "parsedate.h"
 #include "fopen.h"
@@ -155,7 +154,7 @@
 
   do {
     curlx_str_passblanks(&p);
-    if(strncasecompare("max-age", p, 7)) {
+    if(curl_strnequal("max-age", p, 7)) {
       bool quoted = FALSE;
       int rc;
 
@@ -185,7 +184,7 @@
       }
       gotma = TRUE;
     }
-    else if(strncasecompare("includesubdomains", p, 17)) {
+    else if(curl_strnequal("includesubdomains", p, 17)) {
       if(gotinc)
         return CURLE_BAD_FUNCTION_ARGUMENT;
       subdomains = TRUE;
@@ -272,15 +271,15 @@
       if((subdomain && sts->includeSubDomains) && (ntail < hlen)) {
         size_t offs = hlen - ntail;
         if((hostname[offs-1] == '.') &&
-           strncasecompare(&hostname[offs], sts->host, ntail) &&
+           curl_strnequal(&hostname[offs], sts->host, ntail) &&
            (ntail > blen)) {
           /* save the tail match with the longest tail */
           bestsub = sts;
           blen = ntail;
         }
       }
-      /* avoid strcasecompare because the host name is not null-terminated */
-      if((hlen == ntail) && strncasecompare(hostname, sts->host, hlen))
+      /* avoid curl_strequal because the host name is not null-terminated */
+      if((hlen == ntail) && curl_strnequal(hostname, sts->host, hlen))
         return sts;
     }
   }
@@ -581,4 +580,8 @@
   }
 }
 
+#if defined(DEBUGBUILD) || defined(UNITTESTS)
+#undef time
+#endif
+
 #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index 5942d31..e5a0696 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -232,7 +232,7 @@
   connkeep(conn, "HTTP default");
   if(data->state.http_neg.wanted == CURL_HTTP_V3x) {
     /* only HTTP/3, needs to work */
-    CURLcode result = Curl_conn_may_http3(data, conn);
+    CURLcode result = Curl_conn_may_http3(data, conn, conn->transport_wanted);
     if(result)
       return result;
   }
@@ -259,7 +259,7 @@
   for(head = (conn->bits.proxy && data->set.sep_headers) ?
         data->set.proxyheaders : data->set.headers;
       head; head = head->next) {
-    if(strncasecompare(head->data, thisheader, thislen) &&
+    if(curl_strnequal(head->data, thisheader, thislen) &&
        Curl_headersep(head->data[thislen]))
       return head->data;
   }
@@ -862,7 +862,7 @@
 {
   /* the auth string must not have an alnum following */
   size_t n = strlen(auth);
-  return strncasecompare(auth, line, n) && !ISALNUM(line[n]);
+  return curl_strnequal(auth, line, n) && !ISALNUM(line[n]);
 }
 #endif
 
@@ -1482,7 +1482,7 @@
   DEBUGASSERT(header);
   DEBUGASSERT(content);
 
-  if(!strncasecompare(headerline, header, hlen))
+  if(!curl_strnequal(headerline, header, hlen))
     return FALSE; /* does not start with header */
 
   /* pass the header */
@@ -1497,7 +1497,7 @@
     size_t len;
     p = curlx_str(&val);
     for(len = curlx_strlen(&val); len >= curlx_strlen(&val); len--, p++) {
-      if(strncasecompare(p, content, clen))
+      if(curl_strnequal(p, content, clen))
         return TRUE; /* match! */
     }
   }
@@ -1893,7 +1893,7 @@
 
   ptr = Curl_checkheaders(data, STRCONST("Host"));
   if(ptr && (!data->state.this_is_a_follow ||
-             strcasecompare(data->state.first_host, conn->host.name))) {
+             curl_strequal(data->state.first_host, conn->host.name))) {
 #if !defined(CURL_DISABLE_COOKIES)
     /* If we have a given custom Host: header, we extract the hostname in
        order to possibly use it for cookie reasons later on. We only allow the
@@ -1929,7 +1929,7 @@
     }
 #endif
 
-    if(!strcasecompare("Host:", ptr)) {
+    if(!curl_strequal("Host:", ptr)) {
       aptr->host = aprintf("Host:%s\r\n", &ptr[5]);
       if(!aptr->host)
         return CURLE_OUT_OF_MEMORY;
@@ -2005,7 +2005,7 @@
       return CURLE_OUT_OF_MEMORY;
     }
 
-    if(strcasecompare("http", data->state.up.scheme)) {
+    if(curl_strequal("http", data->state.up.scheme)) {
       /* when getting HTTP, we do not want the userinfo the URL */
       uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
       if(uc) {
@@ -2034,7 +2034,7 @@
     if(result)
       return result;
 
-    if(strcasecompare("ftp", data->state.up.scheme)) {
+    if(curl_strequal("ftp", data->state.up.scheme)) {
       if(data->set.proxy_transfer_mode) {
         /* when doing ftp, append ;type=<a|i> if not present */
         char *type = strstr(path, ";type=");
@@ -2443,7 +2443,7 @@
         data->state.aptr.cookiehost : conn->host.name;
       const bool secure_context =
         conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
-        strcasecompare("localhost", host) ||
+        curl_strequal("localhost", host) ||
         !strcmp(host, "127.0.0.1") ||
         !strcmp(host, "::1");
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
@@ -3001,376 +3001,488 @@
    Curl_compareheader(hd, STRCONST(n), STRCONST(v)))
 
 /*
+ * http_header_a() parses a single response header starting with A.
+ */
+static CURLcode http_header_a(struct Curl_easy *data,
+                              const char *hd, size_t hdlen)
+{
+#ifndef CURL_DISABLE_ALTSVC
+  const char *v;
+  struct connectdata *conn = data->conn;
+  v = (data->asi &&
+       (Curl_conn_is_ssl(data->conn, FIRSTSOCKET) ||
+#ifdef DEBUGBUILD
+        /* allow debug builds to circumvent the HTTPS restriction */
+        getenv("CURL_ALTSVC_HTTP")
+#else
+        0
+#endif
+         )) ? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
+  if(v) {
+    /* the ALPN of the current request */
+    struct SingleRequest *k = &data->req;
+    enum alpnid id = (k->httpversion == 30) ? ALPN_h3 :
+      (k->httpversion == 20) ? ALPN_h2 : ALPN_h1;
+    return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
+                             curlx_uitous((unsigned int)conn->remote_port));
+  }
+#else
+  (void)data;
+  (void)hd;
+  (void)hdlen;
+#endif
+  return CURLE_OK;
+}
+
+/*
+ * http_header_c() parses a single response header starting with C.
+ */
+static CURLcode http_header_c(struct Curl_easy *data,
+                              const char *hd, size_t hdlen)
+{
+  struct connectdata *conn = data->conn;
+  struct SingleRequest *k = &data->req;
+  const char *v;
+
+  /* Check for Content-Length: header lines to get size */
+  v = (!k->http_bodyless && !data->set.ignorecl) ?
+    HD_VAL(hd, hdlen, "Content-Length:") : NULL;
+  if(v) {
+    curl_off_t contentlength;
+    int offt = curlx_str_numblanks(&v, &contentlength);
+
+    if(offt == STRE_OK) {
+      k->size = contentlength;
+      k->maxdownload = k->size;
+    }
+    else if(offt == STRE_OVERFLOW) {
+      /* out of range */
+      if(data->set.max_filesize) {
+        failf(data, "Maximum file size exceeded");
+        return CURLE_FILESIZE_EXCEEDED;
+      }
+      streamclose(conn, "overflow content-length");
+      infof(data, "Overflow Content-Length: value");
+    }
+    else {
+      /* negative or just rubbish - bad HTTP */
+      failf(data, "Invalid Content-Length: value");
+      return CURLE_WEIRD_SERVER_REPLY;
+    }
+    return CURLE_OK;
+  }
+  v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ?
+    HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
+  if(v) {
+    /*
+     * Process Content-Encoding. Look for the values: identity,
+     * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
+     * x-compress are the same as gzip and compress. (Sec 3.5 RFC
+     * 2616). zlib cannot handle compress. However, errors are
+     * handled further down when the response body is processed
+     */
+    return Curl_build_unencoding_stack(data, v, FALSE);
+  }
+  /* check for Content-Type: header lines to get the MIME-type */
+  v = HD_VAL(hd, hdlen, "Content-Type:");
+  if(v) {
+    char *contenttype = Curl_copy_header_value(hd);
+    if(!contenttype)
+      return CURLE_OUT_OF_MEMORY;
+    if(!*contenttype)
+      /* ignore empty data */
+      free(contenttype);
+    else {
+      free(data->info.contenttype);
+      data->info.contenttype = contenttype;
+    }
+    return CURLE_OK;
+  }
+  if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
+    /*
+     * [RFC 2616, section 8.1.2.1]
+     * "Connection: close" is HTTP/1.1 language and means that
+     * the connection will close when this request has been
+     * served.
+     */
+    streamclose(conn, "Connection: close used");
+    return CURLE_OK;
+  }
+  if((k->httpversion == 10) &&
+     HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
+    /*
+     * An HTTP/1.0 reply with the 'Connection: keep-alive' line
+     * tells us the connection will be kept alive for our
+     * pleasure. Default action for 1.0 is to close.
+     *
+     * [RFC2068, section 19.7.1] */
+    connkeep(conn, "Connection keep-alive");
+    infof(data, "HTTP/1.0 connection set to keep alive");
+    return CURLE_OK;
+  }
+  v = !k->http_bodyless ? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
+  if(v) {
+    /* Content-Range: bytes [num]-
+       Content-Range: bytes: [num]-
+       Content-Range: [num]-
+       Content-Range: [asterisk]/[total]
+
+       The second format was added since Sun's webserver
+       JavaWebServer/1.1.1 obviously sends the header this way!
+       The third added since some servers use that!
+       The fourth means the requested range was unsatisfied.
+    */
+
+    const char *ptr = v;
+
+    /* Move forward until first digit or asterisk */
+    while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
+      ptr++;
+
+    /* if it truly stopped on a digit */
+    if(ISDIGIT(*ptr)) {
+      if(!curlx_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) &&
+         (data->state.resume_from == k->offset))
+        /* we asked for a resume and we got it */
+        k->content_range = TRUE;
+    }
+    else if(k->httpcode < 300)
+      data->state.resume_from = 0; /* get everything */
+  }
+  return CURLE_OK;
+}
+
+/*
+ * http_header_l() parses a single response header starting with L.
+ */
+static CURLcode http_header_l(struct Curl_easy *data,
+                              const char *hd, size_t hdlen)
+{
+  struct connectdata *conn = data->conn;
+  struct SingleRequest *k = &data->req;
+  const char *v = (!k->http_bodyless &&
+                   (data->set.timecondition || data->set.get_filetime)) ?
+    HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
+  if(v) {
+    k->timeofdoc = Curl_getdate_capped(v);
+    if(data->set.get_filetime)
+      data->info.filetime = k->timeofdoc;
+    return CURLE_OK;
+  }
+  if((k->httpcode >= 300 && k->httpcode < 400) &&
+     HD_IS(hd, hdlen, "Location:") &&
+     !data->req.location) {
+    /* this is the URL that the server advises us to use instead */
+    char *location = Curl_copy_header_value(hd);
+    if(!location)
+      return CURLE_OUT_OF_MEMORY;
+    if(!*location)
+      /* ignore empty data */
+      free(location);
+    else {
+      data->req.location = location;
+
+      if(data->set.http_follow_mode) {
+        CURLcode result;
+        DEBUGASSERT(!data->req.newurl);
+        data->req.newurl = strdup(data->req.location); /* clone */
+        if(!data->req.newurl)
+          return CURLE_OUT_OF_MEMORY;
+
+        /* some cases of POST and PUT etc needs to rewind the data
+           stream at this point */
+        result = http_perhapsrewind(data, conn);
+        if(result)
+          return result;
+
+        /* mark the next request as a followed location: */
+        data->state.this_is_a_follow = TRUE;
+      }
+    }
+  }
+  return CURLE_OK;
+}
+
+/*
+ * http_header_p() parses a single response header starting with P.
+ */
+static CURLcode http_header_p(struct Curl_easy *data,
+                              const char *hd, size_t hdlen)
+{
+  struct SingleRequest *k = &data->req;
+
+#ifndef CURL_DISABLE_PROXY
+  const char *v = HD_VAL(hd, hdlen, "Proxy-Connection:");
+  if(v) {
+    struct connectdata *conn = data->conn;
+    if((k->httpversion == 10) && conn->bits.httpproxy &&
+       HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
+      /*
+       * When an HTTP/1.0 reply comes when using a proxy, the
+       * 'Proxy-Connection: keep-alive' line tells us the
+       * connection will be kept alive for our pleasure.
+       * Default action for 1.0 is to close.
+       */
+      connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
+      infof(data, "HTTP/1.0 proxy connection set to keep alive");
+    }
+    else if((k->httpversion == 11) && conn->bits.httpproxy &&
+            HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
+      /*
+       * We get an HTTP/1.1 response from a proxy and it says it will
+       * close down after this transfer.
+       */
+      connclose(conn, "Proxy-Connection: asked to close after done");
+      infof(data, "HTTP/1.1 proxy connection set close");
+    }
+    return CURLE_OK;
+  }
+#endif
+  if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
+    char *auth = Curl_copy_header_value(hd);
+    CURLcode result;
+    if(!auth)
+      return CURLE_OUT_OF_MEMORY;
+    result = Curl_http_input_auth(data, TRUE, auth);
+    free(auth);
+    return result;
+  }
+#ifdef USE_SPNEGO
+  if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
+    struct connectdata *conn = data->conn;
+    struct negotiatedata *negdata = Curl_auth_nego_get(conn, FALSE);
+    struct auth *authp = &data->state.authhost;
+    if(!negdata)
+      return CURLE_OUT_OF_MEMORY;
+    if(authp->picked == CURLAUTH_NEGOTIATE) {
+      char *persistentauth = Curl_copy_header_value(hd);
+      if(!persistentauth)
+        return CURLE_OUT_OF_MEMORY;
+      negdata->noauthpersist = !!checkprefix("false", persistentauth);
+      negdata->havenoauthpersist = TRUE;
+      infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
+            negdata->noauthpersist, persistentauth);
+      free(persistentauth);
+    }
+  }
+#endif
+  return CURLE_OK;
+}
+
+/*
+ * http_header_r() parses a single response header starting with R.
+ */
+static CURLcode http_header_r(struct Curl_easy *data,
+                              const char *hd, size_t hdlen)
+{
+  const char *v = HD_VAL(hd, hdlen, "Retry-After:");
+  if(v) {
+    /* Retry-After = HTTP-date / delay-seconds */
+    curl_off_t retry_after = 0; /* zero for unknown or "now" */
+    time_t date;
+    curlx_str_passblanks(&v);
+
+    /* try it as a date first, because a date can otherwise start with and
+       get treated as a number */
+    date = Curl_getdate_capped(v);
+
+    if((time_t)-1 != date) {
+      time_t current = time(NULL);
+      if(date >= current)
+        /* convert date to number of seconds into the future */
+        retry_after = date - current;
+    }
+    else
+      /* Try it as a decimal number, ignore errors */
+      (void)curlx_str_number(&v, &retry_after, CURL_OFF_T_MAX);
+    /* limit to 6 hours max. this is not documented so that it can be changed
+       in the future if necessary. */
+    if(retry_after > 21600)
+      retry_after = 21600;
+    data->info.retry_after = retry_after;
+  }
+  return CURLE_OK;
+}
+
+/*
+ * http_header_s() parses a single response header starting with S.
+ */
+static CURLcode http_header_s(struct Curl_easy *data,
+                              const char *hd, size_t hdlen)
+{
+#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_HSTS)
+  struct connectdata *conn = data->conn;
+  const char *v;
+#else
+  (void)data;
+  (void)hd;
+  (void)hdlen;
+#endif
+
+#if !defined(CURL_DISABLE_COOKIES)
+  v = (data->cookies && data->state.cookie_engine) ?
+    HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
+  if(v) {
+    /* If there is a custom-set Host: name, use it here, or else use
+     * real peer hostname. */
+    const char *host = data->state.aptr.cookiehost ?
+      data->state.aptr.cookiehost : conn->host.name;
+    const bool secure_context =
+      conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
+      curl_strequal("localhost", host) ||
+      !strcmp(host, "127.0.0.1") ||
+      !strcmp(host, "::1");
+
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
+                    CURL_LOCK_ACCESS_SINGLE);
+    Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
+                    data->state.up.path, secure_context);
+    Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    return CURLE_OK;
+  }
+#endif
+#ifndef CURL_DISABLE_HSTS
+  /* If enabled, the header is incoming and this is over HTTPS */
+  v = (data->hsts &&
+       (Curl_conn_is_ssl(conn, FIRSTSOCKET) ||
+#ifdef DEBUGBUILD
+        /* allow debug builds to circumvent the HTTPS restriction */
+        getenv("CURL_HSTS_HTTP")
+#else
+        0
+#endif
+         )
+    ) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
+  if(v) {
+    CURLcode check =
+      Curl_hsts_parse(data->hsts, conn->host.name, v);
+    if(check)
+      infof(data, "Illegal STS header skipped");
+#ifdef DEBUGBUILD
+    else
+      infof(data, "Parsed STS header fine (%zu entries)",
+            Curl_llist_count(&data->hsts->list));
+#endif
+  }
+#endif
+
+  return CURLE_OK;
+}
+
+/*
+ * http_header_t() parses a single response header starting with T.
+ */
+static CURLcode http_header_t(struct Curl_easy *data,
+                              const char *hd, size_t hdlen)
+{
+  struct connectdata *conn = data->conn;
+  struct SingleRequest *k = &data->req;
+
+  /* RFC 9112, ch. 6.1
+   * "Transfer-Encoding MAY be sent in a response to a HEAD request or
+   *  in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a
+   *  GET request, neither of which includes a message body, to indicate
+   *  that the origin server would have applied a transfer coding to the
+   *  message body if the request had been an unconditional GET."
+   *
+   * Read: in these cases the 'Transfer-Encoding' does not apply
+   * to any data following the response headers. Do not add any decoders.
+   */
+  const char *v = (!k->http_bodyless &&
+                   (data->state.httpreq != HTTPREQ_HEAD) &&
+                   (k->httpcode != 304)) ?
+    HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
+  if(v) {
+    /* One or more encodings. We check for chunked and/or a compression
+       algorithm. */
+    CURLcode result = Curl_build_unencoding_stack(data, v, TRUE);
+    if(result)
+      return result;
+    if(!k->chunk && data->set.http_transfer_encoding) {
+      /* if this is not chunked, only close can signal the end of this
+       * transfer as Content-Length is said not to be trusted for
+       * transfer-encoding! */
+      connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
+      k->ignore_cl = TRUE;
+    }
+    return CURLE_OK;
+  }
+  v = HD_VAL(hd, hdlen, "Trailer:");
+  if(v) {
+    data->req.resp_trailer = TRUE;
+    return CURLE_OK;
+  }
+  return CURLE_OK;
+}
+
+/*
+ * http_header_w() parses a single response header starting with W.
+ */
+static CURLcode http_header_w(struct Curl_easy *data,
+                              const char *hd, size_t hdlen)
+{
+  struct SingleRequest *k = &data->req;
+  CURLcode result = CURLE_OK;
+
+  if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
+    char *auth = Curl_copy_header_value(hd);
+    if(!auth)
+      return CURLE_OUT_OF_MEMORY;
+    result = Curl_http_input_auth(data, FALSE, auth);
+    free(auth);
+  }
+  return result;
+}
+
+/*
  * http_header() parses a single response header.
  */
 static CURLcode http_header(struct Curl_easy *data,
                             const char *hd, size_t hdlen)
 {
-  struct connectdata *conn = data->conn;
-  CURLcode result;
-  struct SingleRequest *k = &data->req;
-  const char *v;
+  CURLcode result = CURLE_OK;
 
   switch(hd[0]) {
   case 'a':
   case 'A':
-#ifndef CURL_DISABLE_ALTSVC
-    v = (data->asi &&
-         (Curl_conn_is_ssl(data->conn, FIRSTSOCKET) ||
-#ifdef DEBUGBUILD
-          /* allow debug builds to circumvent the HTTPS restriction */
-          getenv("CURL_ALTSVC_HTTP")
-#else
-          0
-#endif
-        )) ? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
-    if(v) {
-      /* the ALPN of the current request */
-      enum alpnid id = (k->httpversion == 30) ? ALPN_h3 :
-                         (k->httpversion == 20) ? ALPN_h2 : ALPN_h1;
-      return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
-                               curlx_uitous((unsigned int)conn->remote_port));
-    }
-#endif
+    result = http_header_a(data, hd, hdlen);
     break;
   case 'c':
   case 'C':
-    /* Check for Content-Length: header lines to get size */
-    v = (!k->http_bodyless && !data->set.ignorecl) ?
-      HD_VAL(hd, hdlen, "Content-Length:") : NULL;
-    if(v) {
-      curl_off_t contentlength;
-      int offt = curlx_str_numblanks(&v, &contentlength);
-
-      if(offt == STRE_OK) {
-        k->size = contentlength;
-        k->maxdownload = k->size;
-      }
-      else if(offt == STRE_OVERFLOW) {
-        /* out of range */
-        if(data->set.max_filesize) {
-          failf(data, "Maximum file size exceeded");
-          return CURLE_FILESIZE_EXCEEDED;
-        }
-        streamclose(conn, "overflow content-length");
-        infof(data, "Overflow Content-Length: value");
-      }
-      else {
-        /* negative or just rubbish - bad HTTP */
-        failf(data, "Invalid Content-Length: value");
-        return CURLE_WEIRD_SERVER_REPLY;
-      }
-      return CURLE_OK;
-    }
-    v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ?
-      HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
-    if(v) {
-      /*
-       * Process Content-Encoding. Look for the values: identity,
-       * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
-       * x-compress are the same as gzip and compress. (Sec 3.5 RFC
-       * 2616). zlib cannot handle compress. However, errors are
-       * handled further down when the response body is processed
-       */
-      return Curl_build_unencoding_stack(data, v, FALSE);
-    }
-    /* check for Content-Type: header lines to get the MIME-type */
-    v = HD_VAL(hd, hdlen, "Content-Type:");
-    if(v) {
-      char *contenttype = Curl_copy_header_value(hd);
-      if(!contenttype)
-        return CURLE_OUT_OF_MEMORY;
-      if(!*contenttype)
-        /* ignore empty data */
-        free(contenttype);
-      else {
-        free(data->info.contenttype);
-        data->info.contenttype = contenttype;
-      }
-      return CURLE_OK;
-    }
-    if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
-      /*
-       * [RFC 2616, section 8.1.2.1]
-       * "Connection: close" is HTTP/1.1 language and means that
-       * the connection will close when this request has been
-       * served.
-       */
-      streamclose(conn, "Connection: close used");
-      return CURLE_OK;
-    }
-    if((k->httpversion == 10) &&
-       HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
-      /*
-       * An HTTP/1.0 reply with the 'Connection: keep-alive' line
-       * tells us the connection will be kept alive for our
-       * pleasure. Default action for 1.0 is to close.
-       *
-       * [RFC2068, section 19.7.1] */
-      connkeep(conn, "Connection keep-alive");
-      infof(data, "HTTP/1.0 connection set to keep alive");
-      return CURLE_OK;
-    }
-    v = !k->http_bodyless ? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
-    if(v) {
-      /* Content-Range: bytes [num]-
-         Content-Range: bytes: [num]-
-         Content-Range: [num]-
-         Content-Range: [asterisk]/[total]
-
-         The second format was added since Sun's webserver
-         JavaWebServer/1.1.1 obviously sends the header this way!
-         The third added since some servers use that!
-         The fourth means the requested range was unsatisfied.
-      */
-
-      const char *ptr = v;
-
-      /* Move forward until first digit or asterisk */
-      while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
-        ptr++;
-
-      /* if it truly stopped on a digit */
-      if(ISDIGIT(*ptr)) {
-        if(!curlx_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) &&
-           (data->state.resume_from == k->offset))
-          /* we asked for a resume and we got it */
-          k->content_range = TRUE;
-      }
-      else if(k->httpcode < 300)
-        data->state.resume_from = 0; /* get everything */
-    }
+    result = http_header_c(data, hd, hdlen);
     break;
   case 'l':
   case 'L':
-    v = (!k->http_bodyless &&
-         (data->set.timecondition || data->set.get_filetime)) ?
-        HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
-    if(v) {
-      k->timeofdoc = Curl_getdate_capped(v);
-      if(data->set.get_filetime)
-        data->info.filetime = k->timeofdoc;
-      return CURLE_OK;
-    }
-    if((k->httpcode >= 300 && k->httpcode < 400) &&
-            HD_IS(hd, hdlen, "Location:") &&
-            !data->req.location) {
-      /* this is the URL that the server advises us to use instead */
-      char *location = Curl_copy_header_value(hd);
-      if(!location)
-        return CURLE_OUT_OF_MEMORY;
-      if(!*location)
-        /* ignore empty data */
-        free(location);
-      else {
-        data->req.location = location;
-
-        if(data->set.http_follow_mode) {
-          DEBUGASSERT(!data->req.newurl);
-          data->req.newurl = strdup(data->req.location); /* clone */
-          if(!data->req.newurl)
-            return CURLE_OUT_OF_MEMORY;
-
-          /* some cases of POST and PUT etc needs to rewind the data
-             stream at this point */
-          result = http_perhapsrewind(data, conn);
-          if(result)
-            return result;
-
-          /* mark the next request as a followed location: */
-          data->state.this_is_a_follow = TRUE;
-        }
-      }
-    }
+    result = http_header_l(data, hd, hdlen);
     break;
   case 'p':
   case 'P':
-#ifndef CURL_DISABLE_PROXY
-    v = HD_VAL(hd, hdlen, "Proxy-Connection:");
-    if(v) {
-      if((k->httpversion == 10) && conn->bits.httpproxy &&
-         HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
-        /*
-         * When an HTTP/1.0 reply comes when using a proxy, the
-         * 'Proxy-Connection: keep-alive' line tells us the
-         * connection will be kept alive for our pleasure.
-         * Default action for 1.0 is to close.
-         */
-        connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
-        infof(data, "HTTP/1.0 proxy connection set to keep alive");
-      }
-      else if((k->httpversion == 11) && conn->bits.httpproxy &&
-              HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
-        /*
-         * We get an HTTP/1.1 response from a proxy and it says it will
-         * close down after this transfer.
-         */
-        connclose(conn, "Proxy-Connection: asked to close after done");
-        infof(data, "HTTP/1.1 proxy connection set close");
-      }
-      return CURLE_OK;
-    }
-#endif
-    if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
-      char *auth = Curl_copy_header_value(hd);
-      if(!auth)
-        return CURLE_OUT_OF_MEMORY;
-      result = Curl_http_input_auth(data, TRUE, auth);
-      free(auth);
-      return result;
-    }
-#ifdef USE_SPNEGO
-    if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
-      struct negotiatedata *negdata = &conn->negotiate;
-      struct auth *authp = &data->state.authhost;
-      if(authp->picked == CURLAUTH_NEGOTIATE) {
-        char *persistentauth = Curl_copy_header_value(hd);
-        if(!persistentauth)
-          return CURLE_OUT_OF_MEMORY;
-        negdata->noauthpersist = !!checkprefix("false", persistentauth);
-        negdata->havenoauthpersist = TRUE;
-        infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
-              negdata->noauthpersist, persistentauth);
-        free(persistentauth);
-      }
-    }
-#endif
+    result = http_header_p(data, hd, hdlen);
     break;
   case 'r':
   case 'R':
-    v = HD_VAL(hd, hdlen, "Retry-After:");
-    if(v) {
-      /* Retry-After = HTTP-date / delay-seconds */
-      curl_off_t retry_after = 0; /* zero for unknown or "now" */
-      time_t date;
-      curlx_str_passblanks(&v);
-
-      /* try it as a date first, because a date can otherwise start with and
-         get treated as a number */
-      date = Curl_getdate_capped(v);
-
-      if((time_t)-1 != date) {
-        time_t current = time(NULL);
-        if(date >= current)
-          /* convert date to number of seconds into the future */
-          retry_after = date - current;
-      }
-      else
-        /* Try it as a decimal number */
-        curlx_str_number(&v, &retry_after, CURL_OFF_T_MAX);
-      /* limit to 6 hours max. this is not documented so that it can be changed
-         in the future if necessary. */
-      if(retry_after > 21600)
-        retry_after = 21600;
-      data->info.retry_after = retry_after;
-      return CURLE_OK;
-    }
+    result = http_header_r(data, hd, hdlen);
     break;
   case 's':
   case 'S':
-#if !defined(CURL_DISABLE_COOKIES)
-    v = (data->cookies && data->state.cookie_engine) ?
-        HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
-    if(v) {
-      /* If there is a custom-set Host: name, use it here, or else use
-       * real peer hostname. */
-      const char *host = data->state.aptr.cookiehost ?
-        data->state.aptr.cookiehost : conn->host.name;
-      const bool secure_context =
-        conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
-        strcasecompare("localhost", host) ||
-        !strcmp(host, "127.0.0.1") ||
-        !strcmp(host, "::1");
-
-      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
-                      CURL_LOCK_ACCESS_SINGLE);
-      Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
-                      data->state.up.path, secure_context);
-      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
-      return CURLE_OK;
-    }
-#endif
-#ifndef CURL_DISABLE_HSTS
-    /* If enabled, the header is incoming and this is over HTTPS */
-    v = (data->hsts &&
-         (Curl_conn_is_ssl(conn, FIRSTSOCKET) ||
-#ifdef DEBUGBUILD
-           /* allow debug builds to circumvent the HTTPS restriction */
-           getenv("CURL_HSTS_HTTP")
-#else
-           0
-#endif
-            )
-        ) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
-    if(v) {
-      CURLcode check =
-        Curl_hsts_parse(data->hsts, conn->host.name, v);
-      if(check)
-        infof(data, "Illegal STS header skipped");
-#ifdef DEBUGBUILD
-      else
-        infof(data, "Parsed STS header fine (%zu entries)",
-              Curl_llist_count(&data->hsts->list));
-#endif
-    }
-#endif
+    result = http_header_s(data, hd, hdlen);
     break;
   case 't':
   case 'T':
-    /* RFC 9112, ch. 6.1
-     * "Transfer-Encoding MAY be sent in a response to a HEAD request or
-     *  in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a
-     *  GET request, neither of which includes a message body, to indicate
-     *  that the origin server would have applied a transfer coding to the
-     *  message body if the request had been an unconditional GET."
-     *
-     * Read: in these cases the 'Transfer-Encoding' does not apply
-     * to any data following the response headers. Do not add any decoders.
-     */
-    v = (!k->http_bodyless &&
-         (data->state.httpreq != HTTPREQ_HEAD) &&
-         (k->httpcode != 304)) ?
-      HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
-    if(v) {
-      /* One or more encodings. We check for chunked and/or a compression
-         algorithm. */
-      result = Curl_build_unencoding_stack(data, v, TRUE);
-      if(result)
-        return result;
-      if(!k->chunk && data->set.http_transfer_encoding) {
-        /* if this is not chunked, only close can signal the end of this
-         * transfer as Content-Length is said not to be trusted for
-         * transfer-encoding! */
-        connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
-        k->ignore_cl = TRUE;
-      }
-      return CURLE_OK;
-    }
-    v = HD_VAL(hd, hdlen, "Trailer:");
-    if(v) {
-      data->req.resp_trailer = TRUE;
-      return CURLE_OK;
-    }
+    result = http_header_t(data, hd, hdlen);
     break;
   case 'w':
   case 'W':
-    if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
-      char *auth = Curl_copy_header_value(hd);
-      if(!auth)
-        return CURLE_OUT_OF_MEMORY;
-      result = Curl_http_input_auth(data, FALSE, auth);
-      free(auth);
-      return result;
-    }
+    result = http_header_w(data, hd, hdlen);
     break;
   }
 
-  if(conn->handler->protocol & CURLPROTO_RTSP) {
-    result = Curl_rtsp_parseheader(data, hd);
-    if(result)
-      return result;
+  if(!result) {
+    struct connectdata *conn = data->conn;
+    if(conn->handler->protocol & CURLPROTO_RTSP)
+      result = Curl_rtsp_parseheader(data, hd);
   }
-  return CURLE_OK;
+  return result;
 }
 
 /*
@@ -3850,9 +3962,8 @@
 out:
   if(last_hd) {
     /* if not written yet, write it now */
-    CURLcode r2 = http_write_header(data, last_hd, last_hd_len);
-    if(!result)
-      result = r2;
+    result = Curl_1st_err(
+      result, http_write_header(data, last_hd, last_hd_len));
   }
   return result;
 }
@@ -4474,7 +4585,7 @@
     if(e->namelen < H2_NON_FIELD[i].namelen)
       return TRUE;
     if(e->namelen == H2_NON_FIELD[i].namelen &&
-       strcasecompare(H2_NON_FIELD[i].name, e->name))
+       curl_strequal(H2_NON_FIELD[i].name, e->name))
       return FALSE;
   }
   return TRUE;
@@ -4565,7 +4676,7 @@
     e = Curl_dynhds_getn(&req->headers, i);
     /* "TE" is special in that it is only permissible when it
      * has only value "trailers". RFC 9113 ch. 8.2.2 */
-    if(e->namelen == 2 && strcasecompare("TE", e->name)) {
+    if(e->namelen == 2 && curl_strequal("TE", e->name)) {
       if(http_TE_has_token(e->value, "trailers"))
         result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
                                  "trailers", sizeof("trailers") - 1);
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index dd82aa9..36dca42 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -36,7 +36,6 @@
 #include "sendf.h"
 #include "select.h"
 #include "curlx/base64.h"
-#include "strcase.h"
 #include "multiif.h"
 #include "url.h"
 #include "urlapi-int.h"
@@ -205,6 +204,9 @@
   }
 }
 
+static CURLcode nw_out_flush(struct Curl_cfilter *cf,
+                             struct Curl_easy *data);
+
 static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
                                    struct Curl_easy *data);
 
@@ -374,27 +376,6 @@
 }
 #endif /* !NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE */
 
-/*
- * Mark this transfer to get "drained".
- */
-static void drain_stream(struct Curl_cfilter *cf,
-                         struct Curl_easy *data,
-                         struct h2_stream_ctx *stream)
-{
-  unsigned char bits;
-
-  (void)cf;
-  bits = CURL_CSELECT_IN;
-  if(!stream->closed &&
-     (!stream->body_eos || !Curl_bufq_is_empty(&stream->sendbuf)))
-    bits |= CURL_CSELECT_OUT;
-  if(stream->closed || (data->state.select_bits != bits)) {
-    CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
-                stream->id, bits);
-    data->state.select_bits = bits;
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
-  }
-}
 
 static CURLcode http2_data_setup(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
@@ -449,8 +430,10 @@
       flush_egress = TRUE;
     }
 
-    if(flush_egress)
-      nghttp2_session_send(ctx->h2);
+    if(flush_egress) {
+      (void)nghttp2_session_send(ctx->h2);
+      (void)nw_out_flush(cf, data);
+    }
   }
 
   Curl_uint_hash_remove(&ctx->streams, data->mid);
@@ -480,33 +463,6 @@
   return rc;
 }
 
-static ssize_t nw_in_reader(void *reader_ctx,
-                              unsigned char *buf, size_t buflen,
-                              CURLcode *err)
-{
-  struct Curl_cfilter *cf = reader_ctx;
-  struct Curl_easy *data = CF_DATA_CURRENT(cf);
-
-  return Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
-}
-
-static ssize_t nw_out_writer(void *writer_ctx,
-                             const unsigned char *buf, size_t buflen,
-                             CURLcode *err)
-{
-  struct Curl_cfilter *cf = writer_ctx;
-  struct Curl_easy *data = CF_DATA_CURRENT(cf);
-
-  if(data) {
-    ssize_t nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf,
-                                         buflen, FALSE, err);
-    if(nwritten > 0)
-      CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten);
-    return nwritten;
-  }
-  return 0;
-}
-
 static ssize_t send_callback(nghttp2_session *h2,
                              const uint8_t *mem, size_t length, int flags,
                              void *userp);
@@ -727,12 +683,12 @@
        not in use by any other transfer, there should not be any data here,
        only "protocol frames" */
     CURLcode result;
-    ssize_t nread = -1;
+    size_t nread;
 
     *input_pending = FALSE;
-    nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
-    if(nread != -1) {
-      CURL_TRC_CF(data, cf, "%zd bytes stray data read before trying "
+    result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
+    if(!result) {
+      CURL_TRC_CF(data, cf, "%zu bytes stray data read before trying "
                   "h2 connection", nread);
       if(h2_process_pending_input(cf, data, &result) < 0)
         /* immediate error, considered dead */
@@ -785,15 +741,16 @@
                              struct Curl_easy *data)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
   (void)data;
   if(Curl_bufq_is_empty(&ctx->outbufq))
     return CURLE_OK;
 
-  nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result);
-  if(nwritten < 0) {
+  result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, NULL, 0,
+                             &nwritten);
+  if(result) {
     if(result == CURLE_AGAIN) {
       CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
                   Curl_bufq_len(&ctx->outbufq));
@@ -816,7 +773,7 @@
   struct Curl_cfilter *cf = userp;
   struct cf_h2_ctx *ctx = cf->ctx;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result = CURLE_OK;
 
   (void)h2;
@@ -824,11 +781,12 @@
   DEBUGASSERT(data);
 
   if(!cf->connected)
-    nwritten = Curl_bufq_write(&ctx->outbufq, buf, blen, &result);
+    result = Curl_bufq_write(&ctx->outbufq, buf, blen, &nwritten);
   else
-    nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
-                                    nw_out_writer, cf, &result);
-  if(nwritten < 0) {
+    result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, buf, blen,
+                               &nwritten);
+
+  if(result) {
     if(result == CURLE_AGAIN) {
       ctx->nw_out_blocked = 1;
       return NGHTTP2_ERR_WOULDBLOCK;
@@ -841,7 +799,8 @@
     ctx->nw_out_blocked = 1;
     return NGHTTP2_ERR_WOULDBLOCK;
   }
-  return nwritten;
+  return (nwritten  > SSIZE_T_MAX) ?
+    NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten;
 }
 
 
@@ -1191,7 +1150,7 @@
     if(stream->status_code / 100 != 1) {
       stream->resp_hds_complete = TRUE;
     }
-    drain_stream(cf, data, stream);
+    Curl_multi_mark_dirty(data);
     break;
   case NGHTTP2_PUSH_PROMISE:
     rv = push_promise(cf, data, &frame->push_promise);
@@ -1214,12 +1173,12 @@
     if(frame->rst_stream.error_code) {
       stream->reset = TRUE;
     }
-    drain_stream(cf, data, stream);
+    Curl_multi_mark_dirty(data);
     break;
   case NGHTTP2_WINDOW_UPDATE:
     if(CURL_WANT_SEND(data) && Curl_bufq_is_empty(&stream->sendbuf)) {
       /* need more data, force processing of transfer */
-      drain_stream(cf, data, stream);
+      Curl_multi_mark_dirty(data);
     }
     else if(!Curl_bufq_is_empty(&stream->sendbuf)) {
       /* resume the potentially suspended stream */
@@ -1245,7 +1204,7 @@
                                 stream->id, NGHTTP2_STREAM_CLOSED);
       stream->closed = TRUE;
     }
-    drain_stream(cf, data, stream);
+    Curl_multi_mark_dirty(data);
   }
   return CURLE_OK;
 }
@@ -1394,11 +1353,8 @@
          * window and *assume* that we treat this like a WINDOW_UPDATE. Some
          * servers send an explicit WINDOW_UPDATE, but not all seem to do that.
          * To be safe, we UNHOLD a stream in order not to stall. */
-        if(CURL_WANT_SEND(data)) {
-          struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
-          if(stream)
-            drain_stream(cf, data, stream);
-        }
+        if(CURL_WANT_SEND(data))
+          Curl_multi_mark_dirty(data);
       }
       break;
     }
@@ -1543,7 +1499,7 @@
               stream_id, nghttp2_http2_strerror(error_code), error_code);
   else
     CURL_TRC_CF(data_s, cf, "[%d] CLOSED", stream_id);
-  drain_stream(cf, data_s, stream);
+  Curl_multi_mark_dirty(data_s);
 
   /* remove `data_s` from the nghttp2 stream */
   rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
@@ -1641,9 +1597,9 @@
       if(!check)
         /* no memory */
         return NGHTTP2_ERR_CALLBACK_FAILURE;
-      if(!strcasecompare(check, (const char *)value) &&
+      if(!curl_strequal(check, (const char *)value) &&
          ((cf->conn->remote_port != cf->conn->given->defport) ||
-          !strcasecompare(cf->conn->host.name, (const char *)value))) {
+          !curl_strequal(cf->conn->host.name, (const char *)value))) {
         /* This is push is not for the same authority that was asked for in
          * the URL. RFC 7540 section 8.2 says: "A client MUST treat a
          * PUSH_PROMISE for which the server is not authoritative as a stream
@@ -1737,7 +1693,7 @@
     }
     /* if we receive data for another handle, wake that up */
     if(CF_DATA_CURRENT(cf) != data_s)
-      Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+      Curl_multi_mark_dirty(data_s);
 
     CURL_TRC_CF(data_s, cf, "[%d] status: HTTP/2 %03d",
                 stream->id, stream->status_code);
@@ -1764,7 +1720,7 @@
   }
   /* if we receive data for another handle, wake that up */
   if(CF_DATA_CURRENT(cf) != data_s)
-    Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+    Curl_multi_mark_dirty(data_s);
 
   CURL_TRC_CF(data_s, cf, "[%d] header: %.*s: %.*s",
               stream->id, (int)namelen, name, (int)valuelen, value);
@@ -1785,6 +1741,7 @@
   struct h2_stream_ctx *stream = NULL;
   CURLcode result;
   ssize_t nread;
+  size_t n;
   (void)source;
 
   (void)cf;
@@ -1803,12 +1760,14 @@
   if(!stream)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result);
-  if(nread < 0) {
+  result = Curl_bufq_read(&stream->sendbuf, buf, length, &n);
+  if(result) {
     if(result != CURLE_AGAIN)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     nread = 0;
   }
+  else
+    nread = (ssize_t)n;
 
   CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d",
               stream_id, length, stream->body_eos, nread, result);
@@ -1874,20 +1833,20 @@
   return result;
 }
 
-static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
-                                         struct Curl_easy *data,
-                                         struct h2_stream_ctx *stream,
-                                         CURLcode *err)
+static CURLcode http2_handle_stream_close(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data,
+                                          struct h2_stream_ctx *stream,
+                                          size_t *pnlen)
 {
-  ssize_t rv = 0;
+  CURLcode result;
 
+  *pnlen = 0;
   if(stream->error == NGHTTP2_REFUSED_STREAM) {
     CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
                 "connection", stream->id);
     connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
     data->state.refused_stream = TRUE;
-    *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
-    return -1;
+    return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
   }
   else if(stream->error != NGHTTP2_NO_ERROR) {
     if(stream->resp_hds_complete && data->req.no_body) {
@@ -1896,27 +1855,23 @@
                   stream->id, nghttp2_http2_strerror(stream->error),
                   stream->error);
       stream->close_handled = TRUE;
-      *err = CURLE_OK;
-      goto out;
+      return CURLE_OK;
     }
     failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
           stream->id, nghttp2_http2_strerror(stream->error),
           stream->error);
-    *err = CURLE_HTTP2_STREAM;
-    return -1;
+    return CURLE_HTTP2_STREAM;
   }
   else if(stream->reset) {
     failf(data, "HTTP/2 stream %u was reset", stream->id);
-    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
-    return -1;
+    return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
   }
 
   if(!stream->bodystarted) {
     failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
           " all response header fields, treated as error",
           stream->id);
-    *err = CURLE_HTTP2_STREAM;
-    return -1;
+    return CURLE_HTTP2_STREAM;
   }
 
   if(Curl_dynhds_count(&stream->resp_trailers)) {
@@ -1924,37 +1879,36 @@
     struct dynbuf dbuf;
     size_t i;
 
-    *err = CURLE_OK;
+    result = CURLE_OK;
     curlx_dyn_init(&dbuf, DYN_TRAILERS);
     for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) {
       e = Curl_dynhds_getn(&stream->resp_trailers, i);
       if(!e)
         break;
       curlx_dyn_reset(&dbuf);
-      *err = curlx_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a",
+      result = curlx_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a",
                             (int)e->namelen, e->name,
                             (int)e->valuelen, e->value);
-      if(*err)
+      if(result)
         break;
       Curl_debug(data, CURLINFO_HEADER_IN, curlx_dyn_ptr(&dbuf),
                  curlx_dyn_len(&dbuf));
-      *err = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
-                               curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf));
-      if(*err)
+      result = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
+                                 curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf));
+      if(result)
         break;
     }
     curlx_dyn_free(&dbuf);
-    if(*err)
+    if(result)
       goto out;
   }
 
   stream->close_handled = TRUE;
-  *err = CURLE_OK;
-  rv = 0;
+  result = CURLE_OK;
 
 out:
-  CURL_TRC_CF(data, cf, "handle_stream_close -> %zd, %d", rv, *err);
-  return rv;
+  CURL_TRC_CF(data, cf, "handle_stream_close -> %d, %zu", result, *pnlen);
+  return result;
 }
 
 static int sweight_wanted(const struct Curl_easy *data)
@@ -1997,7 +1951,7 @@
  * Flush any out data pending in the network buffer.
  */
 static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data)
+                                   struct Curl_easy *data)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
@@ -2037,36 +1991,36 @@
   return nw_out_flush(cf, data);
 }
 
-static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                           struct h2_stream_ctx *stream,
-                           char *buf, size_t len, CURLcode *err)
+static CURLcode stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                            struct h2_stream_ctx *stream,
+                            char *buf, size_t len, size_t *pnread)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
-  ssize_t nread = -1;
+  CURLcode result = CURLE_AGAIN;
 
   (void)buf;
-  *err = CURLE_AGAIN;
+  (void)len;
+  *pnread = 0;
+
   if(stream->xfer_result) {
     CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id);
-    *err = stream->xfer_result;
-    nread = -1;
+    result = stream->xfer_result;
   }
   else if(stream->closed) {
     CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
-    nread = http2_handle_stream_close(cf, data, stream, err);
+    result = http2_handle_stream_close(cf, data, stream, pnread);
   }
   else if(stream->reset ||
           (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
           (ctx->rcvd_goaway && ctx->remote_max_sid < stream->id)) {
     CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
-    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
-    nread = -1;
+    result = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
   }
 
-  if(nread < 0 && *err != CURLE_AGAIN)
-    CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d",
-                stream->id, len, nread, *err);
-  return nread;
+  if(result && (result != CURLE_AGAIN))
+    CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %d, %zu",
+                stream->id, len, result, *pnread);
+  return result;
 }
 
 static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
@@ -2076,7 +2030,7 @@
   struct cf_h2_ctx *ctx = cf->ctx;
   struct h2_stream_ctx *stream;
   CURLcode result = CURLE_OK;
-  ssize_t nread;
+  size_t nread;
 
   if(should_close_session(ctx)) {
     CURL_TRC_CF(data, cf, "progress ingress, session is closed");
@@ -2102,12 +2056,12 @@
        * this may leave data in underlying buffers that will not
        * be consumed. */
       if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data))
-        drain_stream(cf, data, stream);
+        Curl_multi_mark_dirty(data);
       break;
     }
 
-    nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result);
-    if(nread < 0) {
+    result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
+    if(result) {
       if(result != CURLE_AGAIN) {
         failf(data, "Failed receiving HTTP2 data: %d(%s)", result,
               curl_easy_strerror(result));
@@ -2121,9 +2075,8 @@
       break;
     }
     else {
-      CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", nread);
-      data_max_bytes = (data_max_bytes > (size_t)nread) ?
-        (data_max_bytes - (size_t)nread) : 0;
+      CURL_TRC_CF(data, cf, "[0] ingress: read %zu bytes", nread);
+      data_max_bytes = (data_max_bytes > nread) ? (data_max_bytes - nread) : 0;
     }
 
     if(h2_process_pending_input(cf, data, &result))
@@ -2140,15 +2093,15 @@
   return CURLE_OK;
 }
 
-static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          char *buf, size_t len, CURLcode *err)
+static CURLcode cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           char *buf, size_t len, size_t *pnread)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
-  CURLcode result;
+  CURLcode result, r2;
   struct cf_call_data save;
 
+  *pnread = 0;
   if(!stream) {
     /* Abnormal call sequence: either this transfer has never opened a stream
      * (unlikely) or the transfer has been done, cleaned up its resources, but
@@ -2156,51 +2109,49 @@
      * is for such a case. */
     failf(data, "http/2 recv on a transfer never opened "
           "or already cleared, mid=%u", data->mid);
-    *err = CURLE_HTTP2;
-    return -1;
+    return CURLE_HTTP2;
   }
 
   CF_DATA_SAVE(save, cf, data);
 
-  nread = stream_recv(cf, data, stream, buf, len, err);
-  if(nread < 0 && *err != CURLE_AGAIN)
+  result = stream_recv(cf, data, stream, buf, len, pnread);
+  if(result && (result != CURLE_AGAIN))
     goto out;
 
-  if(nread < 0) {
-    *err = h2_progress_ingress(cf, data, len);
-    if(*err)
+  if(result) {
+    result = h2_progress_ingress(cf, data, len);
+    if(result)
       goto out;
 
-    nread = stream_recv(cf, data, stream, buf, len, err);
+    result = stream_recv(cf, data, stream, buf, len, pnread);
   }
 
-  if(nread > 0) {
+  if(*pnread > 0) {
     /* Now that we transferred this to the upper layer, we report
      * the actual amount of DATA consumed to the H2 session, so
      * that it adjusts stream flow control */
-    nghttp2_session_consume(ctx->h2, stream->id, (size_t)nread);
+    nghttp2_session_consume(ctx->h2, stream->id, *pnread);
     if(stream->closed) {
       CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id);
-      drain_stream(cf, data, stream);
+      Curl_multi_mark_dirty(data);
     }
   }
 
 out:
-  result = h2_progress_egress(cf, data);
-  if(result == CURLE_AGAIN) {
+  r2 = h2_progress_egress(cf, data);
+  if(r2 == CURLE_AGAIN) {
     /* pending data to send, need to be called again. Ideally, we
      * monitor the socket for POLLOUT, but when not SENDING
      * any more, we force processing of the transfer. */
     if(!CURL_WANT_SEND(data))
-      drain_stream(cf, data, stream);
+      Curl_multi_mark_dirty(data);
   }
-  else if(result) {
-    *err = result;
-    nread = -1;
+  else if(r2) {
+    result = r2;
   }
-  CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, "
+  CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu, "
               "window=%d/%d, connection %d/%d",
-              stream->id, len, nread, *err,
+              stream->id, len, result, *pnread,
               nghttp2_session_get_stream_effective_recv_data_length(
                 ctx->h2, stream->id),
               nghttp2_session_get_stream_effective_local_window_size(
@@ -2209,7 +2160,7 @@
               HTTP2_HUGE_WINDOW_SIZE);
 
   CF_DATA_RESTORE(cf, save);
-  return nread;
+  return result;
 }
 
 static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
@@ -2219,7 +2170,7 @@
                                CURLcode *err)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
-  ssize_t nwritten;
+  size_t nwritten;
 
   if(stream->closed) {
     if(stream->resp_hds_complete) {
@@ -2241,11 +2192,11 @@
     return -1;
   }
 
-  nwritten = Curl_bufq_write(&stream->sendbuf, buf, blen, err);
-  if(nwritten < 0)
+  *err = Curl_bufq_write(&stream->sendbuf, buf, blen, &nwritten);
+  if(*err)
     return -1;
 
-  if(eos && (blen == (size_t)nwritten))
+  if(eos && (blen == nwritten))
     stream->body_eos = TRUE;
 
   if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) {
@@ -2256,13 +2207,13 @@
       return -1;
     }
   }
-  return nwritten;
+  return (ssize_t)nwritten;
 }
 
-static ssize_t h2_submit(struct h2_stream_ctx **pstream,
-                         struct Curl_cfilter *cf, struct Curl_easy *data,
-                         const void *buf, size_t len,
-                         bool eos, CURLcode *err)
+static CURLcode h2_submit(struct h2_stream_ctx **pstream,
+                          struct Curl_cfilter *cf, struct Curl_easy *data,
+                          const void *buf, size_t len,
+                          bool eos, size_t *pnwritten)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
   struct h2_stream_ctx *stream = NULL;
@@ -2274,36 +2225,34 @@
   int32_t stream_id;
   nghttp2_priority_spec pri_spec;
   ssize_t nwritten;
+  CURLcode result = CURLE_OK;
 
+  *pnwritten = 0;
   Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
 
-  *err = http2_data_setup(cf, data, &stream);
-  if(*err) {
-    nwritten = -1;
+  result = http2_data_setup(cf, data, &stream);
+  if(result)
     goto out;
-  }
 
-  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
+  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result);
   if(nwritten < 0)
     goto out;
+  *pnwritten = (size_t)nwritten;
   if(!stream->h1.done) {
     /* need more data */
     goto out;
   }
   DEBUGASSERT(stream->h1.req);
 
-  *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
-  if(*err) {
-    nwritten = -1;
+  result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
+  if(result)
     goto out;
-  }
   /* no longer needed */
   Curl_h1_req_parse_free(&stream->h1);
 
   nva = Curl_dynhds_to_nva(&h2_headers, &nheader);
   if(!nva) {
-    *err = CURLE_OUT_OF_MEMORY;
-    nwritten = -1;
+    result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
 
@@ -2329,8 +2278,7 @@
   if(stream_id < 0) {
     CURL_TRC_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
                 nghttp2_strerror(stream_id), stream_id);
-    *err = CURLE_SEND_ERROR;
-    nwritten = -1;
+    result = CURLE_SEND_ERROR;
     goto out;
   }
 
@@ -2357,48 +2305,46 @@
 
   stream->id = stream_id;
 
-  body = (const char *)buf + nwritten;
-  bodylen = len - nwritten;
+  body = (const char *)buf + *pnwritten;
+  bodylen = len - *pnwritten;
 
   if(bodylen || eos) {
-    ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, err);
+    ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, &result);
     if(n >= 0)
-      nwritten += n;
-    else if(*err == CURLE_AGAIN)
-      *err = CURLE_OK;
-    else if(*err != CURLE_AGAIN) {
-      *err = CURLE_SEND_ERROR;
-      nwritten = -1;
-      goto out;
+      *pnwritten += n;
+    else if(result == CURLE_AGAIN)
+      result = CURLE_OK;
+    else {
+      result = CURLE_SEND_ERROR;
     }
   }
 
 out:
-  CURL_TRC_CF(data, cf, "[%d] submit -> %zd, %d",
-              stream ? stream->id : -1, nwritten, *err);
+  CURL_TRC_CF(data, cf, "[%d] submit -> %d, %zu",
+              stream ? stream->id : -1, result, *pnwritten);
   Curl_safefree(nva);
   *pstream = stream;
   Curl_dynhds_free(&h2_headers);
-  return nwritten;
+  return result;
 }
 
-static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                          const void *buf, size_t len, bool eos,
-                          CURLcode *err)
+static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                           const void *buf, size_t len, bool eos,
+                           size_t *pnwritten)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
   struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
   struct cf_call_data save;
   ssize_t nwritten;
-  CURLcode result;
+  CURLcode result = CURLE_OK, r2;
 
   CF_DATA_SAVE(save, cf, data);
+  *pnwritten = 0;
 
   if(!stream || stream->id == -1) {
-    nwritten = h2_submit(&stream, cf, data, buf, len, eos, err);
-    if(nwritten < 0) {
+    result = h2_submit(&stream, cf, data, buf, len, eos, pnwritten);
+    if(result)
       goto out;
-    }
     DEBUGASSERT(stream);
   }
   else if(stream->body_eos) {
@@ -2407,35 +2353,35 @@
      * to trigger flushing again.
      * If this works, we report to have written `len` bytes. */
     DEBUGASSERT(eos);
-    nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, err);
+    nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, &result);
     CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %zd, %d, eos=%d",
-                stream->id, nwritten, *err, eos);
+                stream->id, nwritten, result, eos);
     if(nwritten < 0) {
       goto out;
     }
-    nwritten = len;
+    *pnwritten = len;
   }
   else {
-    nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, err);
+    nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, &result);
     CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %zd, %d, eos=%d",
-                stream->id, len, nwritten, *err, eos);
+                stream->id, len, nwritten, result, eos);
+    if(nwritten >= 0)
+      *pnwritten = (size_t)nwritten;
   }
 
   /* Call the nghttp2 send loop and flush to write ALL buffered data,
    * headers and/or request body completely out to the network */
-  result = h2_progress_egress(cf, data);
+  r2 = h2_progress_egress(cf, data);
 
   /* if the stream has been closed in egress handling (nghttp2 does that
    * when it does not like the headers, for example */
   if(stream && stream->closed) {
     infof(data, "stream %u closed", stream->id);
-    *err = CURLE_SEND_ERROR;
-    nwritten = -1;
+    result = CURLE_SEND_ERROR;
     goto out;
   }
-  else if(result && (result != CURLE_AGAIN)) {
-    *err = result;
-    nwritten = -1;
+  else if(r2 && (r2 != CURLE_AGAIN)) {
+    result = r2;
     goto out;
   }
 
@@ -2443,21 +2389,20 @@
     /* nghttp2 thinks this session is done. If the stream has not been
      * closed, this is an error state for out transfer */
     if(stream && stream->closed) {
-      nwritten = http2_handle_stream_close(cf, data, stream, err);
+      result = http2_handle_stream_close(cf, data, stream, pnwritten);
     }
     else {
       CURL_TRC_CF(data, cf, "send: nothing to do in this session");
-      *err = CURLE_HTTP2;
-      nwritten = -1;
+      result = CURLE_HTTP2;
     }
   }
 
 out:
   if(stream) {
-    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, "
+    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, "
                 "eos=%d, h2 windows %d-%d (stream-conn), "
                 "buffers %zu-%zu (stream-conn)",
-                stream->id, len, nwritten, *err,
+                stream->id, len, result, *pnwritten,
                 stream->body_eos,
                 nghttp2_session_get_stream_remote_window_size(
                   ctx->h2, stream->id),
@@ -2466,14 +2411,14 @@
                 Curl_bufq_len(&ctx->outbufq));
   }
   else {
-    CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, "
+    CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zu, "
                 "connection-window=%d, nw_send_buffer(%zu)",
-                len, nwritten, *err,
+                len, result, *pnwritten,
                 nghttp2_session_get_remote_window_size(ctx->h2),
                 Curl_bufq_len(&ctx->outbufq));
   }
   CF_DATA_RESTORE(cf, save);
-  return nwritten;
+  return result;
 }
 
 static CURLcode cf_h2_flush(struct Curl_cfilter *cf,
@@ -2716,8 +2661,7 @@
        * not. We may have already buffered and exhausted the new window
        * by operating on things in flight during the handling of other
        * transfers. */
-      drain_stream(cf, data, stream);
-      Curl_expire(data, 0, EXPIRE_RUN_NOW);
+      Curl_multi_mark_dirty(data);
     }
     CURL_TRC_CF(data, cf, "[%d] stream now %spaused", stream->id,
                 pause ? "" : "un");
@@ -2769,15 +2713,16 @@
                            bool *input_pending)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
-  CURLcode result;
+  bool alive;
   struct cf_call_data save;
 
+  *input_pending = FALSE;
   CF_DATA_SAVE(save, cf, data);
-  result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending));
+  alive = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending));
   CURL_TRC_CF(data, cf, "conn alive -> %d, input_pending=%d",
-              result, *input_pending);
+              alive, *input_pending);
   CF_DATA_RESTORE(cf, save);
-  return result;
+  return alive;
 }
 
 static CURLcode cf_h2_keep_alive(struct Curl_cfilter *cf,
@@ -2805,7 +2750,7 @@
     DEBUGASSERT(pres1);
 
     CF_DATA_SAVE(save, cf, data);
-    if(nghttp2_session_check_request_allowed(ctx->h2) == 0) {
+    if(!ctx->h2 || !nghttp2_session_check_request_allowed(ctx->h2)) {
       /* the limit is what we have in use right now */
       effective_max = CONN_ATTACHED(cf->conn);
     }
@@ -2848,7 +2793,6 @@
   cf_h2_connect,
   cf_h2_close,
   cf_h2_shutdown,
-  Curl_cf_def_get_host,
   cf_h2_adjust_pollset,
   cf_h2_data_pending,
   cf_h2_send,
@@ -3001,17 +2945,17 @@
     /* Remaining data from the protocol switch reply is already using
      * the switched protocol, ie. HTTP/2. We add that to the network
      * inbufq. */
-    ssize_t copied;
+    size_t copied;
 
-    copied = Curl_bufq_write(&ctx->inbufq,
-                             (const unsigned char *)mem, nread, &result);
-    if(copied < 0) {
+    result = Curl_bufq_write(&ctx->inbufq,
+                             (const unsigned char *)mem, nread, &copied);
+    if(result) {
       failf(data, "error on copying HTTP Upgrade response: %d", result);
       return CURLE_RECV_ERROR;
     }
-    if((size_t)copied < nread) {
+    if(copied < nread) {
       failf(data, "connection buffer size could not take all data "
-            "from HTTP Upgrade response header: copied=%zd, datalen=%zu",
+            "from HTTP Upgrade response header: copied=%zu, datalen=%zu",
             copied, nread);
       return CURLE_HTTP2;
     }
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
index 7425382..92c0c1f 100644
--- a/Utilities/cmcurl/lib/http_aws_sigv4.c
+++ b/Utilities/cmcurl/lib/http_aws_sigv4.c
@@ -537,8 +537,8 @@
 }
 
 UNITTEST CURLcode canon_path(const char *q, size_t len,
-                              struct dynbuf *new_path,
-                              bool do_uri_encode)
+                             struct dynbuf *new_path,
+                             bool do_uri_encode)
 {
   CURLcode result = CURLE_OK;
 
diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c
index 5bec3b3..2c0b7e1 100644
--- a/Utilities/cmcurl/lib/http_negotiate.c
+++ b/Utilities/cmcurl/lib/http_negotiate.c
@@ -39,6 +39,20 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+
+static void http_auth_nego_reset(struct connectdata *conn,
+                                 struct negotiatedata *neg_ctx,
+                                 bool proxy)
+{
+  if(proxy)
+    conn->proxy_negotiate_state = GSS_AUTHNONE;
+  else
+    conn->http_negotiate_state = GSS_AUTHNONE;
+  if(neg_ctx)
+    Curl_auth_cleanup_spnego(neg_ctx);
+}
+
+
 CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
                               bool proxy, const char *header)
 {
@@ -62,7 +76,6 @@
     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
               data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
     host = conn->http_proxy.host.name;
-    neg_ctx = &conn->proxyneg;
     state = conn->proxy_negotiate_state;
 #else
     return CURLE_NOT_BUILT_IN;
@@ -74,10 +87,13 @@
     service = data->set.str[STRING_SERVICE_NAME] ?
               data->set.str[STRING_SERVICE_NAME] : "HTTP";
     host = conn->host.name;
-    neg_ctx = &conn->negotiate;
     state = conn->http_negotiate_state;
   }
 
+  neg_ctx = Curl_auth_nego_get(conn, proxy);
+  if(!neg_ctx)
+    return CURLE_OUT_OF_MEMORY;
+
   /* Not set means empty */
   if(!userp)
     userp = "";
@@ -94,12 +110,12 @@
   if(!len) {
     if(state == GSS_AUTHSUCC) {
       infof(data, "Negotiate auth restarted");
-      Curl_http_auth_cleanup_negotiate(conn);
+      http_auth_nego_reset(conn, neg_ctx, proxy);
     }
     else if(state != GSS_AUTHNONE) {
       /* The server rejected our authentication and has not supplied any more
       negotiation mechanisms */
-      Curl_http_auth_cleanup_negotiate(conn);
+      http_auth_nego_reset(conn, neg_ctx, proxy);
       return CURLE_LOGIN_DENIED;
     }
   }
@@ -116,7 +132,7 @@
     result = Curl_ssl_get_channel_binding(
       data, FIRSTSOCKET, &neg_ctx->channel_binding_data);
     if(result) {
-      Curl_http_auth_cleanup_negotiate(conn);
+      http_auth_nego_reset(conn, neg_ctx, proxy);
       return result;
     }
   }
@@ -134,7 +150,7 @@
 #endif
 
   if(result)
-    Curl_http_auth_cleanup_negotiate(conn);
+    http_auth_nego_reset(conn, neg_ctx, proxy);
 
   return result;
 }
@@ -152,7 +168,6 @@
 
   if(proxy) {
 #ifndef CURL_DISABLE_PROXY
-    neg_ctx = &conn->proxyneg;
     authp = &data->state.authproxy;
     state = &conn->proxy_negotiate_state;
 #else
@@ -160,10 +175,12 @@
 #endif
   }
   else {
-    neg_ctx = &conn->negotiate;
     authp = &data->state.authhost;
     state = &conn->http_negotiate_state;
   }
+  neg_ctx = Curl_auth_nego_get(conn, proxy);
+  if(!neg_ctx)
+    return CURLE_OUT_OF_MEMORY;
 
   authp->done = FALSE;
 
@@ -184,7 +201,7 @@
     if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
       infof(data, "Curl_output_negotiate, "
             "no persistent authentication: cleanup existing context");
-      Curl_http_auth_cleanup_negotiate(conn);
+      http_auth_nego_reset(conn, neg_ctx, proxy);
     }
     if(!neg_ctx->context) {
       result = Curl_input_negotiate(data, conn, proxy, "Negotiate");
@@ -249,13 +266,4 @@
   return CURLE_OK;
 }
 
-void Curl_http_auth_cleanup_negotiate(struct connectdata *conn)
-{
-  conn->http_negotiate_state = GSS_AUTHNONE;
-  conn->proxy_negotiate_state = GSS_AUTHNONE;
-
-  Curl_auth_cleanup_spnego(&conn->negotiate);
-  Curl_auth_cleanup_spnego(&conn->proxyneg);
-}
-
 #endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/http_negotiate.h b/Utilities/cmcurl/lib/http_negotiate.h
index 76d8356..ad7c43d 100644
--- a/Utilities/cmcurl/lib/http_negotiate.h
+++ b/Utilities/cmcurl/lib/http_negotiate.h
@@ -34,10 +34,6 @@
 CURLcode Curl_output_negotiate(struct Curl_easy *data,
                                struct connectdata *conn, bool proxy);
 
-void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
-
-#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */
-#define Curl_http_auth_cleanup_negotiate(x)
 #endif
 
 #endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c
index e6a3b17..0dff8f3 100644
--- a/Utilities/cmcurl/lib/http_ntlm.c
+++ b/Utilities/cmcurl/lib/http_ntlm.c
@@ -60,17 +60,18 @@
                                                 header */
 {
   /* point to the correct struct with this */
-  struct ntlmdata *ntlm;
   curlntlm *state;
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
 
-  ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
   state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
 
   if(checkprefix("NTLM", header)) {
-    header += strlen("NTLM");
+    struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, proxy);
+    if(!ntlm)
+      return CURLE_FAILED_INIT;
 
+    header += strlen("NTLM");
     curlx_str_passblanks(&header);
     if(*header) {
       unsigned char *hdr;
@@ -93,11 +94,11 @@
     else {
       if(*state == NTLMSTATE_LAST) {
         infof(data, "NTLM auth restarted");
-        Curl_http_auth_cleanup_ntlm(conn);
+        Curl_auth_ntlm_remove(conn, proxy);
       }
       else if(*state == NTLMSTATE_TYPE3) {
         infof(data, "NTLM handshake rejected");
-        Curl_http_auth_cleanup_ntlm(conn);
+        Curl_auth_ntlm_remove(conn, proxy);
         *state = NTLMSTATE_NONE;
         return CURLE_REMOTE_ACCESS_DENIED;
       }
@@ -150,7 +151,6 @@
     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
       data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
     hostname = conn->http_proxy.host.name;
-    ntlm = &conn->proxyntlm;
     state = &conn->proxy_ntlm_state;
     authp = &data->state.authproxy;
 #else
@@ -164,10 +164,12 @@
     service = data->set.str[STRING_SERVICE_NAME] ?
       data->set.str[STRING_SERVICE_NAME] : "HTTP";
     hostname = conn->host.name;
-    ntlm = &conn->ntlm;
     state = &conn->http_ntlm_state;
     authp = &data->state.authhost;
   }
+  ntlm = Curl_auth_ntlm_get(conn, proxy);
+  if(!ntlm)
+    return CURLE_OUT_OF_MEMORY;
   authp->done = FALSE;
 
   /* not set means empty */
@@ -178,10 +180,10 @@
     passwdp = "";
 
 #ifdef USE_WINDOWS_SSPI
-  if(!Curl_hSecDll) {
+  if(!Curl_pSecFn) {
     /* not thread safe and leaks - use curl_global_init() to avoid */
     CURLcode err = Curl_sspi_global_init();
-    if(!Curl_hSecDll)
+    if(!Curl_pSecFn)
       return err;
   }
 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
@@ -200,9 +202,8 @@
   case NTLMSTATE_TYPE1:
   default: /* for the weird cases we (re)start here */
     /* Create a type-1 message */
-    result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp,
-                                                 service, hostname,
-                                                 ntlm, &ntlmmsg);
+    result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, service,
+                                                 hostname, ntlm, &ntlmmsg);
     if(!result) {
       DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
       result = curlx_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
@@ -258,10 +259,4 @@
   return result;
 }
 
-void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
-{
-  Curl_auth_cleanup_ntlm(&conn->ntlm);
-  Curl_auth_cleanup_ntlm(&conn->proxyntlm);
-}
-
 #endif /* !CURL_DISABLE_HTTP && USE_NTLM */
diff --git a/Utilities/cmcurl/lib/http_ntlm.h b/Utilities/cmcurl/lib/http_ntlm.h
index c1cf057..b38ff82 100644
--- a/Utilities/cmcurl/lib/http_ntlm.h
+++ b/Utilities/cmcurl/lib/http_ntlm.h
@@ -35,10 +35,6 @@
 /* this is for creating NTLM header output */
 CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy);
 
-void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
-
-#else /* !CURL_DISABLE_HTTP && USE_NTLM */
-#define Curl_http_auth_cleanup_ntlm(x)
 #endif
 
 #endif /* HEADER_CURL_HTTP_NTLM_H */
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index 3df6329..6f435a8 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -38,7 +38,6 @@
 #include "cf-h1-proxy.h"
 #include "cf-h2-proxy.h"
 #include "connect.h"
-#include "strcase.h"
 #include "vtls/vtls.h"
 #include "transfer.h"
 #include "multiif.h"
@@ -53,7 +52,7 @@
 static bool hd_name_eq(const char *n1, size_t n1len,
                        const char *n2, size_t n2len)
 {
-  return (n1len == n2len) ? strncasecompare(n1, n2, n1len) : FALSE;
+  return (n1len == n2len) ? curl_strnequal(n1, n2, n1len) : FALSE;
 }
 
 static CURLcode dynhds_add_custom(struct Curl_easy *data,
@@ -383,21 +382,21 @@
   return result;
 }
 
-void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf,
-                                 struct Curl_easy *data,
-                                 const char **phost,
-                                 const char **pdisplay_host,
-                                 int *pport)
+CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  int query, int *pres1, void *pres2)
 {
-  (void)data;
-  if(!cf->connected) {
-    *phost = cf->conn->http_proxy.host.name;
-    *pdisplay_host = cf->conn->http_proxy.host.dispname;
-    *pport = (int)cf->conn->http_proxy.port;
+  switch(query) {
+  case CF_QUERY_HOST_PORT:
+    *pres1 = (int)cf->conn->http_proxy.port;
+    *((const char **)pres2) = cf->conn->http_proxy.host.name;
+    return CURLE_OK;
+  default:
+    break;
   }
-  else {
-    cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
-  }
+  return cf->next ?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
 }
 
 static void http_proxy_cf_destroy(struct Curl_cfilter *cf,
@@ -443,7 +442,6 @@
   http_proxy_cf_connect,
   http_proxy_cf_close,
   Curl_cf_def_shutdown,
-  Curl_cf_http_proxy_get_host,
   Curl_cf_def_adjust_pollset,
   Curl_cf_def_data_pending,
   Curl_cf_def_send,
@@ -451,7 +449,7 @@
   Curl_cf_def_cntrl,
   Curl_cf_def_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
-  Curl_cf_def_query,
+  Curl_cf_http_proxy_query,
 };
 
 CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h
index 2e91ff2..e6ab2ba 100644
--- a/Utilities/cmcurl/lib/http_proxy.h
+++ b/Utilities/cmcurl/lib/http_proxy.h
@@ -48,18 +48,16 @@
 /* Default proxy timeout in milliseconds */
 #define PROXY_TIMEOUT (3600*1000)
 
-void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf,
-                                 struct Curl_easy *data,
-                                 const char **phost,
-                                 const char **pdisplay_host,
-                                 int *pport);
+CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf,
+                                  struct Curl_easy *data,
+                                  int query, int *pres1, void *pres2);
 
 CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
                                          struct Curl_easy *data);
 
 extern struct Curl_cftype Curl_cft_http_proxy;
 
-#endif /* !CURL_DISABLE_PROXY  && !CURL_DISABLE_HTTP */
+#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
 
 #define IS_HTTPS_PROXY(t) (((t) == CURLPROXY_HTTPS) ||  \
                            ((t) == CURLPROXY_HTTPS2))
diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c
index 6da68ef..d685290 100644
--- a/Utilities/cmcurl/lib/if2ip.c
+++ b/Utilities/cmcurl/lib/if2ip.c
@@ -52,8 +52,7 @@
 #  include <inet.h>
 #endif
 
-#include "inet_ntop.h"
-#include "strcase.h"
+#include "curlx/inet_ntop.h"
 #include "if2ip.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -117,7 +116,7 @@
     for(iface = head; iface != NULL; iface = iface->ifa_next) {
       if(iface->ifa_addr) {
         if(iface->ifa_addr->sa_family == af) {
-          if(strcasecompare(iface->ifa_name, interf)) {
+          if(curl_strequal(iface->ifa_name, interf)) {
             void *addr;
             const char *ip;
             char scope[12] = "";
@@ -162,13 +161,13 @@
               addr =
                 &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
             res = IF2IP_FOUND;
-            ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
+            ip = curlx_inet_ntop(af, addr, ipstr, sizeof(ipstr));
             msnprintf(buf, buf_size, "%s%s", ip, scope);
             break;
           }
         }
         else if((res == IF2IP_NOT_FOUND) &&
-                strcasecompare(iface->ifa_name, interf)) {
+                curl_strequal(iface->ifa_name, interf)) {
           res = IF2IP_AF_NOT_SUPPORTED;
         }
       }
@@ -235,7 +234,7 @@
 
   s = (struct sockaddr_in *)(void *)&req.ifr_addr;
   memcpy(&in, &s->sin_addr, sizeof(in));
-  r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
+  r = curlx_inet_ntop(s->sin_family, &in, buf, buf_size);
 
   sclose(dummy);
   if(!r)
diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
index fc38a5b..f25176b 100644
--- a/Utilities/cmcurl/lib/imap.c
+++ b/Utilities/cmcurl/lib/imap.c
@@ -302,7 +302,7 @@
 
   /* Does the command name match and is it followed by a space character or at
      the end of line? */
-  if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) &&
+  if(line + cmd_len <= end && curl_strnequal(line, cmd, cmd_len) &&
      (line[cmd_len] == ' ' || line + cmd_len + 2 == end))
     return TRUE;
 
@@ -358,16 +358,16 @@
       case IMAP_LIST:
         if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
            (imap->custom && !imap_matchresp(line, len, imap->custom) &&
-            (!strcasecompare(imap->custom, "STORE") ||
+            (!curl_strequal(imap->custom, "STORE") ||
              !imap_matchresp(line, len, "FETCH")) &&
-            !strcasecompare(imap->custom, "SELECT") &&
-            !strcasecompare(imap->custom, "EXAMINE") &&
-            !strcasecompare(imap->custom, "SEARCH") &&
-            !strcasecompare(imap->custom, "EXPUNGE") &&
-            !strcasecompare(imap->custom, "LSUB") &&
-            !strcasecompare(imap->custom, "UID") &&
-            !strcasecompare(imap->custom, "GETQUOTAROOT") &&
-            !strcasecompare(imap->custom, "NOOP")))
+            !curl_strequal(imap->custom, "SELECT") &&
+            !curl_strequal(imap->custom, "EXAMINE") &&
+            !curl_strequal(imap->custom, "SEARCH") &&
+            !curl_strequal(imap->custom, "EXPUNGE") &&
+            !curl_strequal(imap->custom, "LSUB") &&
+            !curl_strequal(imap->custom, "UID") &&
+            !curl_strequal(imap->custom, "GETQUOTAROOT") &&
+            !curl_strequal(imap->custom, "NOOP")))
           return FALSE;
         break;
 
@@ -1239,7 +1239,7 @@
   else if(imapcode == IMAP_RESP_OK) {
     /* Check if the UIDVALIDITY has been specified and matches */
     if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
-       !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
+       !curl_strequal(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
       failf(data, "Mailbox UIDVALIDITY has changed");
       result = CURLE_REMOTE_FILE_NOT_FOUND;
     }
@@ -1347,9 +1347,6 @@
     else {
       /* IMAP download */
       data->req.maxdownload = size;
-      /* force a recv/send check of this connection, as the data might've been
-       read off the socket already */
-      data->state.select_bits = CURL_CSELECT_IN;
       Curl_xfer_setup1(data, CURL_XFER_RECV, size, FALSE);
     }
   }
@@ -1693,9 +1690,9 @@
   /* Determine if the requested mailbox (with the same UIDVALIDITY if set)
      has already been selected on this connection */
   if(imap->mailbox && imapc->mailbox &&
-     strcasecompare(imap->mailbox, imapc->mailbox) &&
+     curl_strequal(imap->mailbox, imapc->mailbox) &&
      (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
-      strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)))
+      curl_strequal(imap->uidvalidity, imapc->mailbox_uidvalidity)))
     selected = TRUE;
 
   /* Start the first command in the DO phase */
@@ -1780,18 +1777,14 @@
   (void)data;
   if(imapc) {
     /* We cannot send quit unconditionally. If this connection is stale or
-       bad in any way, sending quit and waiting around here will make the
+       bad in any way (pingpong has pending data to send),
+       sending quit and waiting around here will make the
        disconnect wait in vain and cause more problems than we need to. */
-
-    /* The IMAP session may or may not have been allocated/setup at this
-       point! */
-    if(!dead_connection && conn->bits.protoconnstart) {
+    if(!dead_connection && conn->bits.protoconnstart &&
+       !Curl_pp_needs_flush(data, &imapc->pp)) {
       if(!imap_perform_logout(data, imapc))
         (void)imap_block_statemach(data, imapc, TRUE); /* ignore errors */
     }
-
-    /* Cleanup the SASL module */
-    Curl_sasl_cleanup(conn, imapc->sasl.authused);
   }
   return CURLE_OK;
 }
@@ -2079,12 +2072,12 @@
     while(*ptr && *ptr != ';')
       ptr++;
 
-    if(strncasecompare(key, "AUTH=+LOGIN", 11)) {
+    if(curl_strnequal(key, "AUTH=+LOGIN", 11)) {
       /* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */
       prefer_login = TRUE;
       imapc->sasl.prefmech = SASL_AUTH_NONE;
     }
-    else if(strncasecompare(key, "AUTH=", 5)) {
+    else if(curl_strnequal(key, "AUTH=", 5)) {
       prefer_login = FALSE;
       result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
                                                value, ptr - value);
@@ -2189,35 +2182,35 @@
        PARTIAL) stripping of the trailing slash character if it is present.
 
        Note: Unknown parameters trigger a URL_MALFORMAT error. */
-    if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) {
+    if(curl_strequal(name, "UIDVALIDITY") && !imap->uidvalidity) {
       if(valuelen > 0 && value[valuelen - 1] == '/')
         value[valuelen - 1] = '\0';
 
       imap->uidvalidity = value;
       value = NULL;
     }
-    else if(strcasecompare(name, "UID") && !imap->uid) {
+    else if(curl_strequal(name, "UID") && !imap->uid) {
       if(valuelen > 0 && value[valuelen - 1] == '/')
         value[valuelen - 1] = '\0';
 
       imap->uid = value;
       value = NULL;
     }
-    else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) {
+    else if(curl_strequal(name, "MAILINDEX") && !imap->mindex) {
       if(valuelen > 0 && value[valuelen - 1] == '/')
         value[valuelen - 1] = '\0';
 
       imap->mindex = value;
       value = NULL;
     }
-    else if(strcasecompare(name, "SECTION") && !imap->section) {
+    else if(curl_strequal(name, "SECTION") && !imap->section) {
       if(valuelen > 0 && value[valuelen - 1] == '/')
         value[valuelen - 1] = '\0';
 
       imap->section = value;
       value = NULL;
     }
-    else if(strcasecompare(name, "PARTIAL") && !imap->partial) {
+    else if(curl_strequal(name, "PARTIAL") && !imap->partial) {
       if(valuelen > 0 && value[valuelen - 1] == '/')
         value[valuelen - 1] = '\0';
 
diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c
index 9ebba4e..b5effa2 100644
--- a/Utilities/cmcurl/lib/krb5.c
+++ b/Utilities/cmcurl/lib/krb5.c
@@ -56,7 +56,6 @@
 #include "transfer.h"
 #include "curl_krb5.h"
 #include "curlx/warnless.h"
-#include "strcase.h"
 #include "strdup.h"
 
 /* The last 3 #include files should be in this order */
@@ -215,12 +214,14 @@
   gss_ctx_id_t *context = app_data;
   struct gss_channel_bindings_struct chan;
   size_t base64_sz = 0;
-  struct sockaddr_in *remote_addr =
-    (struct sockaddr_in *)CURL_UNCONST(&conn->remote_addr->curl_sa_addr);
+  const struct Curl_sockaddr_ex *remote_addr =
+    Curl_conn_get_remote_addr(data, FIRSTSOCKET);
+  struct sockaddr_in *remote_in_addr = remote_addr ?
+    (struct sockaddr_in *)CURL_UNCONST(&remote_addr->curl_sa_addr) : NULL;
   char *stringp;
   struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN);
 
-  if(!ftpc)
+  if(!ftpc || !remote_in_addr)
     return -2;
 
   if(getsockname(conn->sock[FIRSTSOCKET],
@@ -232,7 +233,7 @@
   chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr;
   chan.acceptor_addrtype = GSS_C_AF_INET;
   chan.acceptor_address.length = l - 4;
-  chan.acceptor_address.value = &remote_addr->sin_addr.s_addr;
+  chan.acceptor_address.value = &remote_in_addr->sin_addr.s_addr;
   chan.application_data.length = 0;
   chan.application_data.value = NULL;
 
@@ -384,7 +385,8 @@
   OM_uint32 min;
   gss_ctx_id_t *context = app_data;
   if(*context != GSS_C_NO_CONTEXT) {
-    OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER);
+    OM_uint32 maj = Curl_gss_delete_sec_context(&min, context,
+                                                GSS_C_NO_BUFFER);
     (void)maj;
     DEBUGASSERT(maj == GSS_S_COMPLETE);
   }
@@ -479,19 +481,18 @@
 {
   char *to_p = to;
   CURLcode result;
-  ssize_t nread = 0;
+  size_t nread = 0;
 
   while(len > 0) {
     result = Curl_conn_recv(data, sockindex, to_p, len, &nread);
-    if(nread > 0) {
-      len -= nread;
-      to_p += nread;
-    }
-    else {
-      if(result == CURLE_AGAIN)
-        continue;
+    if(result == CURLE_AGAIN)
+      continue;
+    if(result)
       return result;
-    }
+    if(nread > len)
+      return CURLE_RECV_ERROR;
+    len -= nread;
+    to_p += nread;
   }
   return CURLE_OK;
 }
@@ -523,8 +524,8 @@
   return CURLE_OK;
 }
 
-static CURLcode read_data(struct Curl_easy *data, int sockindex,
-                          struct krb5buffer *buf)
+static CURLcode krb5_read_data(struct Curl_easy *data, int sockindex,
+                               struct krb5buffer *buf)
 {
   struct connectdata *conn = data->conn;
   int len;
@@ -579,52 +580,49 @@
 }
 
 /* Matches Curl_recv signature */
-static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
-                        char *buffer, size_t len, CURLcode *err)
+static CURLcode sec_recv(struct Curl_easy *data, int sockindex,
+                         char *buffer, size_t len, size_t *pnread)
 {
-  size_t bytes_read;
-  size_t total_read = 0;
   struct connectdata *conn = data->conn;
-
-  *err = CURLE_OK;
+  CURLcode result = CURLE_OK;
+  size_t bytes_read;
 
   /* Handle clear text response. */
-  if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) {
-    ssize_t nread;
-    *err = Curl_conn_recv(data, sockindex, buffer, len, &nread);
-    return nread;
-  }
+  if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
+    return Curl_conn_recv(data, sockindex, buffer, len, pnread);
 
   if(conn->in_buffer.eof_flag) {
     conn->in_buffer.eof_flag = 0;
-    return 0;
+    *pnread = 0;
+    return CURLE_OK;
   }
 
   bytes_read = buffer_read(&conn->in_buffer, buffer, len);
-  len -= bytes_read;
-  total_read += bytes_read;
   buffer += bytes_read;
+  len -= bytes_read;
+  *pnread += bytes_read;
 
   while(len > 0) {
-    if(read_data(data, sockindex, &conn->in_buffer))
-      return -1;
+    result = krb5_read_data(data, sockindex, &conn->in_buffer);
+    if(result)
+      return result;
     if(curlx_dyn_len(&conn->in_buffer.buf) == 0) {
-      if(bytes_read > 0)
+      if(*pnread > 0)
         conn->in_buffer.eof_flag = 1;
-      return bytes_read;
+      return result;
     }
     bytes_read = buffer_read(&conn->in_buffer, buffer, len);
-    len -= bytes_read;
-    total_read += bytes_read;
     buffer += bytes_read;
+    len -= bytes_read;
+    *pnread += bytes_read;
   }
-  return total_read;
+  return result;
 }
 
 /* Send |length| bytes from |from| to the |sockindex| socket taking care of
    encoding and negotiating with the server. |from| can be NULL. */
 static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
-                        int sockindex, const char *from, int length)
+                        int sockindex, const char *from, size_t length)
 {
   int bytes, htonl_bytes; /* 32-bit integers for htonl */
   char *buffer = NULL;
@@ -642,8 +640,8 @@
     else
       prot_level = conn->command_prot;
   }
-  bytes = conn->mech->encode(conn->app_data, from, length, (int)prot_level,
-                             (void **)&buffer);
+  bytes = conn->mech->encode(conn->app_data, from, (int)length,
+                             (int)prot_level, (void **)&buffer);
   if(!buffer || bytes <= 0)
     return; /* error */
 
@@ -677,34 +675,36 @@
   free(buffer);
 }
 
-static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
-                         int sockindex, const char *buffer, size_t length)
+static CURLcode sec_write(struct Curl_easy *data, int sockindex,
+                          const char *buffer, size_t length,
+                          size_t *pnwritten)
 {
-  ssize_t tx = 0, len = conn->buffer_size;
+  struct connectdata *conn = data->conn;
+  size_t len = conn->buffer_size;
 
+  *pnwritten = 0;
   if(len <= 0)
     len = length;
   while(length) {
-    if(length < (size_t)len)
+    if(length < len)
       len = length;
 
-    do_sec_send(data, conn, sockindex, buffer, curlx_sztosi(len));
+    /* WTF: this ignores all errors writing to the socket */
+    do_sec_send(data, conn, sockindex, buffer, len);
     length -= len;
     buffer += len;
-    tx += len;
+    *pnwritten += len;
   }
-  return tx;
+  return CURLE_OK;
 }
 
 /* Matches Curl_send signature */
-static ssize_t sec_send(struct Curl_easy *data, int sockindex,
-                        const void *buffer, size_t len, bool eos,
-                        CURLcode *err)
+static CURLcode sec_send(struct Curl_easy *data, int sockindex,
+                         const void *buffer, size_t len, bool eos,
+                         size_t *pnwritten)
 {
-  struct connectdata *conn = data->conn;
   (void)eos; /* unused */
-  *err = CURLE_OK;
-  return sec_write(data, conn, sockindex, buffer, len);
+  return sec_write(data, sockindex, buffer, len, pnwritten);
 }
 
 int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index c1be2f4..40e72af 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -88,7 +88,6 @@
 #include "escape.h"
 #include "progress.h"
 #include "transfer.h"
-#include "strcase.h"
 #include "curlx/strparse.h"
 #include "curl_ldap.h"
 #include "curlx/multibyte.h"
@@ -393,7 +392,7 @@
     if(conn->ssl_config.verifypeer) {
       /* OpenLDAP SDK supports BASE64 files. */
       if((data->set.ssl.cert_type) &&
-         (!strcasecompare(data->set.ssl.cert_type, "PEM"))) {
+         (!curl_strequal(data->set.ssl.cert_type, "PEM"))) {
         failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type");
         result = CURLE_SSL_CERTPROBLEM;
         goto quit;
@@ -748,15 +747,15 @@
  */
 static int str2scope(const char *p)
 {
-  if(strcasecompare(p, "one"))
+  if(curl_strequal(p, "one"))
     return LDAP_SCOPE_ONELEVEL;
-  if(strcasecompare(p, "onetree"))
+  if(curl_strequal(p, "onetree"))
     return LDAP_SCOPE_ONELEVEL;
-  if(strcasecompare(p, "base"))
+  if(curl_strequal(p, "base"))
     return LDAP_SCOPE_BASE;
-  if(strcasecompare(p, "sub"))
+  if(curl_strequal(p, "sub"))
     return LDAP_SCOPE_SUBTREE;
-  if(strcasecompare(p, "subtree"))
+  if(curl_strequal(p, "subtree"))
     return LDAP_SCOPE_SUBTREE;
   return -1;
 }
@@ -801,7 +800,7 @@
   if(!data ||
      !data->state.up.path ||
      data->state.up.path[0] != '/' ||
-     !strncasecompare("LDAP", data->state.up.scheme, 4))
+     !curl_strnequal("LDAP", data->state.up.scheme, 4))
     return LDAP_INVALID_SYNTAX;
 
   ludp->lud_scope = LDAP_SCOPE_BASE;
diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c
index 8293442..c9a7d4a 100644
--- a/Utilities/cmcurl/lib/llist.c
+++ b/Utilities/cmcurl/lib/llist.c
@@ -181,7 +181,8 @@
 /*
  * @unittest: 1300
  */
-void
+UNITTEST void Curl_node_uremove(struct Curl_llist_node *, void *);
+UNITTEST void
 Curl_node_uremove(struct Curl_llist_node *e, void *user)
 {
   struct Curl_llist *list;
diff --git a/Utilities/cmcurl/lib/llist.h b/Utilities/cmcurl/lib/llist.h
index 597c0e0..0a2bc9a 100644
--- a/Utilities/cmcurl/lib/llist.h
+++ b/Utilities/cmcurl/lib/llist.h
@@ -57,7 +57,6 @@
                             const void *, struct Curl_llist_node *node);
 void Curl_llist_append(struct Curl_llist *,
                        const void *, struct Curl_llist_node *node);
-void Curl_node_uremove(struct Curl_llist_node *, void *);
 void Curl_node_remove(struct Curl_llist_node *);
 void Curl_llist_destroy(struct Curl_llist *, void *);
 
@@ -76,7 +75,7 @@
 void *Curl_node_elem(struct Curl_llist_node *n);
 
 /* Remove the node from the list and return the custom data
- * from a Curl_llist_node. Will NOT incoke a registered `dtor`. */
+ * from a Curl_llist_node. Will NOT invoke a registered `dtor`. */
 void *Curl_node_take_elem(struct Curl_llist_node *);
 
 /* Curl_node_next() returns the next element in a list from a given
diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c
index b351726..bdcdcbb 100644
--- a/Utilities/cmcurl/lib/memdebug.c
+++ b/Utilities/cmcurl/lib/memdebug.c
@@ -30,8 +30,6 @@
 
 #include "urldata.h"
 
-#define MEMDEBUG_NODEFINES /* do not redefine the standard functions */
-
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -70,7 +68,7 @@
   if(curl_dbg_logfile &&
      curl_dbg_logfile != stderr &&
      curl_dbg_logfile != stdout) {
-    fclose(curl_dbg_logfile);
+    (fclose)(curl_dbg_logfile);
   }
   curl_dbg_logfile = NULL;
 }
@@ -80,7 +78,11 @@
 {
   if(!curl_dbg_logfile) {
     if(logname && *logname)
-      curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT);
+#ifdef CURL_FOPEN
+      curl_dbg_logfile = CURL_FOPEN(logname, FOPEN_WRITETEXT);
+#else
+      curl_dbg_logfile = (fopen)(logname, FOPEN_WRITETEXT);
+#endif
     else
       curl_dbg_logfile = stderr;
 #ifdef MEMDEBUG_LOG_SYNC
@@ -302,14 +304,14 @@
 }
 
 curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
-                             int line, const char *source)
+                              int line, const char *source)
 {
   curl_socket_t sockfd;
 
   if(countcheck("socket", line, source))
     return CURL_SOCKET_BAD;
 
-  sockfd = socket(domain, type, protocol);
+  sockfd = (socket)(domain, type, protocol);
 
   if(source && (sockfd != CURL_SOCKET_BAD))
     curl_dbg_log("FD %s:%d socket() = %" FMT_SOCKET_T "\n",
@@ -326,7 +328,7 @@
   SEND_TYPE_RETV rc;
   if(countcheck("send", line, source))
     return -1;
-  rc = send(sockfd, buf, len, flags);
+  rc = (send)(sockfd, buf, len, flags);
   if(source)
     curl_dbg_log("SEND %s:%d send(%lu) = %ld\n",
                 source, line, (unsigned long)len, (long)rc);
@@ -340,7 +342,7 @@
   RECV_TYPE_RETV rc;
   if(countcheck("recv", line, source))
     return -1;
-  rc = recv(sockfd, buf, len, flags);
+  rc = (recv)(sockfd, buf, len, flags);
   if(source)
     curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n",
                 source, line, (unsigned long)len, (long)rc);
@@ -349,10 +351,10 @@
 
 #ifdef HAVE_SOCKETPAIR
 int curl_dbg_socketpair(int domain, int type, int protocol,
-                       curl_socket_t socket_vector[2],
-                       int line, const char *source)
+                        curl_socket_t socket_vector[2],
+                        int line, const char *source)
 {
-  int res = socketpair(domain, type, protocol, socket_vector);
+  int res = (socketpair)(domain, type, protocol, socket_vector);
 
   if(source && (0 == res))
     curl_dbg_log("FD %s:%d socketpair() = "
@@ -364,12 +366,12 @@
 #endif
 
 curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
-                             int line, const char *source)
+                              int line, const char *source)
 {
   struct sockaddr *addr = (struct sockaddr *)saddr;
   curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
 
-  curl_socket_t sockfd = accept(s, addr, addrlen);
+  curl_socket_t sockfd = (accept)(s, addr, addrlen);
 
   if(source && (sockfd != CURL_SOCKET_BAD))
     curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n",
@@ -386,7 +388,7 @@
   struct sockaddr *addr = (struct sockaddr *)saddr;
   curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
 
-  curl_socket_t sockfd = accept4(s, addr, addrlen, flags);
+  curl_socket_t sockfd = (accept4)(s, addr, addrlen, flags);
 
   if(source && (sockfd != CURL_SOCKET_BAD))
     curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n",
@@ -407,7 +409,7 @@
 /* this is our own defined way to close sockets on *ALL* platforms */
 int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source)
 {
-  int res = sclose(sockfd);
+  int res = CURL_SCLOSE(sockfd);
   curl_dbg_mark_sclose(sockfd, line, source);
   return res;
 }
@@ -416,7 +418,12 @@
 FILE *curl_dbg_fopen(const char *file, const char *mode,
                      int line, const char *source)
 {
-  FILE *res = fopen(file, mode);
+  FILE *res;
+#ifdef CURL_FOPEN
+  res = CURL_FOPEN(file, mode);
+#else
+  res = (fopen)(file, mode);
+#endif
 
   if(source)
     curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
@@ -429,7 +436,7 @@
 FILE *curl_dbg_fdopen(int filedes, const char *mode,
                       int line, const char *source)
 {
-  FILE *res = fdopen(filedes, mode);
+  FILE *res = (fdopen)(filedes, mode);
   if(source)
     curl_dbg_log("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
                  source, line, filedes, mode, (void *)res);
@@ -446,7 +453,7 @@
     curl_dbg_log("FILE %s:%d fclose(%p)\n",
                  source, line, (void *)file);
 
-  res = fclose(file);
+  res = (fclose)(file);
 
   return res;
 }
@@ -469,7 +476,7 @@
     nchars = (int)sizeof(buf) - 1;
 
   if(nchars > 0)
-    fwrite(buf, 1, (size_t)nchars, curl_dbg_logfile);
+    (fwrite)(buf, 1, (size_t)nchars, curl_dbg_logfile);
 }
 
 #endif /* CURLDEBUG */
diff --git a/Utilities/cmcurl/lib/memdebug.h b/Utilities/cmcurl/lib/memdebug.h
index 11b250d..03b04b1 100644
--- a/Utilities/cmcurl/lib/memdebug.h
+++ b/Utilities/cmcurl/lib/memdebug.h
@@ -56,8 +56,6 @@
 #  define ALLOC_SIZE2(n, s)
 #endif
 
-#define CURL_MT_LOGFNAME_BUFSIZE 512
-
 /* Avoid redundant redeclaration warnings with modern compilers, when including
    this header multiple times. */
 #ifndef HEADER_CURL_MEMDEBUG_H_EXTERNS
@@ -126,8 +124,6 @@
 
 #endif /* HEADER_CURL_MEMDEBUG_H_EXTERNS */
 
-#ifndef MEMDEBUG_NODEFINES
-
 /* Set this symbol on the command-line, recompile all lib-sources */
 #undef strdup
 #define strdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
@@ -145,34 +141,29 @@
 #define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__)
 
 #ifdef _WIN32
-#  ifdef UNICODE
-#    undef wcsdup
-#    define wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
-#    undef _wcsdup
-#    define _wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
-#    undef _tcsdup
-#    define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
-#  else
-#    undef _tcsdup
-#    define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
-#  endif
+#undef _tcsdup
+#ifdef UNICODE
+#define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__)
+#else
+#define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
 #endif
+#endif /* _WIN32 */
 
 #undef socket
-#define socket(domain,type,protocol)\
- curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__)
+#define socket(domain,type,protocol) \
+  curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__)
 #undef accept /* for those with accept as a macro */
-#define accept(sock,addr,len)\
- curl_dbg_accept(sock, addr, len, __LINE__, __FILE__)
+#define accept(sock,addr,len) \
+  curl_dbg_accept(sock, addr, len, __LINE__, __FILE__)
 #ifdef HAVE_ACCEPT4
 #undef accept4 /* for those with accept4 as a macro */
-#define accept4(sock,addr,len,flags)\
- curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__)
+#define accept4(sock,addr,len,flags) \
+  curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__)
 #endif
 #ifdef HAVE_SOCKETPAIR
-#define socketpair(domain,type,protocol,socket_vector)\
- curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \
-                     __LINE__, __FILE__)
+#define socketpair(domain,type,protocol,socket_vector) \
+  curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \
+                      __LINE__, __FILE__)
 #endif
 
 /* sclose is probably already defined, redefine it! */
@@ -185,10 +176,9 @@
 #define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__)
 #undef fdopen
 #define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__)
+#undef fclose
 #define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__)
 
-#endif /* MEMDEBUG_NODEFINES */
-
 #endif /* CURLDEBUG */
 
 /*
diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c
index c90c348..06cd221 100644
--- a/Utilities/cmcurl/lib/mime.c
+++ b/Utilities/cmcurl/lib/mime.c
@@ -32,6 +32,7 @@
 #include "curlx/warnless.h"
 #include "urldata.h"
 #include "sendf.h"
+#include "transfer.h"
 #include "strdup.h"
 #include "curlx/base64.h"
 
@@ -45,7 +46,6 @@
 
 #include "rand.h"
 #include "slist.h"
-#include "strcase.h"
 #include "curlx/dynbuf.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -67,12 +67,12 @@
 
 /* Encoders. */
 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
-                                curl_mimepart *part);
+                               curl_mimepart *part);
 static curl_off_t encoder_nop_size(curl_mimepart *part);
 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
                                 curl_mimepart *part);
 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
-                                curl_mimepart *part);
+                                  curl_mimepart *part);
 static curl_off_t encoder_base64_size(curl_mimepart *part);
 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
                               curl_mimepart *part);
@@ -335,7 +335,7 @@
 {
   char *value = NULL;
 
-  if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
+  if(curl_strnequal(hdr->data, lbl, len) && hdr->data[len] == ':')
     for(value = hdr->data + len + 1; *value == ' '; value++)
       ;
   return value;
@@ -433,7 +433,7 @@
 
 /* Base64 content encoder. */
 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
-                                curl_mimepart *part)
+                                  curl_mimepart *part)
 {
   struct mime_encoder_state *st = &part->encstate;
   size_t cursize = 0;
@@ -1478,7 +1478,7 @@
     return CURLE_OK;    /* Removing current encoder. */
 
   for(mep = encoders; mep->name; mep++)
-    if(strcasecompare(encoding, mep->name)) {
+    if(curl_strequal(encoding, mep->name)) {
       part->encoder = mep;
       result = CURLE_OK;
     }
@@ -1742,7 +1742,7 @@
     for(i = 0; i < CURL_ARRAYSIZE(ctts); i++) {
       size_t len2 = strlen(ctts[i].extension);
 
-      if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
+      if(len1 >= len2 && curl_strequal(nameend - len2, ctts[i].extension))
         return ctts[i].type;
     }
   }
@@ -1752,7 +1752,7 @@
 static bool content_type_match(const char *contenttype,
                                const char *target, size_t len)
 {
-  if(contenttype && strncasecompare(contenttype, target, len))
+  if(contenttype && curl_strnequal(contenttype, target, len))
     switch(contenttype[len]) {
     case '\0':
     case '\t':
@@ -1825,7 +1825,7 @@
   if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
     if(!disposition)
       if(part->filename || part->name ||
-        (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
+        (contenttype && !curl_strnequal(contenttype, "multipart/", 10)))
           disposition = DISPOSITION_DEFAULT;
     if(disposition && curl_strequal(disposition, "attachment") &&
      !part->name && !part->filename)
@@ -1962,6 +1962,7 @@
                              size_t *pnread, bool *peos)
 {
   struct cr_mime_ctx *ctx = reader->ctx;
+  CURLcode result = CURLE_OK;
   size_t nread;
   char tmp[256];
 
@@ -1990,15 +1991,12 @@
   }
 
   if(!Curl_bufq_is_empty(&ctx->tmpbuf)) {
-    CURLcode result = CURLE_OK;
-    ssize_t n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen,
-                               &result);
-    if(n < 0) {
+    result = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &nread);
+    if(result) {
       ctx->errored = TRUE;
       ctx->error_result = result;
       return result;
     }
-    nread = (size_t)n;
   }
   else if(blen <= 4) {
     /* Curl_mime_read() may go into an infinite loop when reading
@@ -2008,22 +2006,20 @@
     CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen);
     nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part);
     if(nread <= sizeof(tmp)) {
-      CURLcode result = CURLE_OK;
-      ssize_t n = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread,
-                                  &result);
-      if(n < 0) {
+      size_t n;
+      result = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread, &n);
+      if(result) {
         ctx->errored = TRUE;
         ctx->error_result = result;
         return result;
       }
       /* stored it, read again */
-      n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &result);
-      if(n < 0) {
+      result = Curl_bufq_cread(&ctx->tmpbuf, buf, blen, &nread);
+      if(result) {
         ctx->errored = TRUE;
         ctx->error_result = result;
         return result;
       }
-      nread = (size_t)n;
     }
   }
   else
@@ -2051,14 +2047,15 @@
     *peos = FALSE;
     ctx->errored = TRUE;
     ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
-    return CURLE_ABORTED_BY_CALLBACK;
+    result = CURLE_ABORTED_BY_CALLBACK;
+    break;
 
   case CURL_READFUNC_PAUSE:
     /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
     CURL_TRC_READ(data, "cr_mime_read(len=%zu), paused by callback", blen);
-    data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
     *pnread = 0;
     *peos = FALSE;
+    result = Curl_xfer_pause_send(data, TRUE);
     break; /* nothing was read */
 
   case STOP_FILLING:
@@ -2068,7 +2065,8 @@
     *peos = FALSE;
     ctx->errored = TRUE;
     ctx->error_result = CURLE_READ_ERROR;
-    return CURLE_READ_ERROR;
+    result = CURLE_READ_ERROR;
+    break;
 
   default:
     if(nread > blen) {
@@ -2090,8 +2088,8 @@
 
   CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T
                 ", read=%"FMT_OFF_T") -> %d, %zu, %d",
-                blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos);
-  return CURLE_OK;
+                blen, ctx->total_len, ctx->read_len, result, *pnread, *peos);
+  return result;
 }
 
 static bool cr_mime_needs_rewind(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c
index 77e7334..90f857d 100644
--- a/Utilities/cmcurl/lib/mqtt.c
+++ b/Utilities/cmcurl/lib/mqtt.c
@@ -240,7 +240,7 @@
 
 /* add the passwd to the CONNECT packet */
 static int add_passwd(const char *passwd, const size_t plen,
-                       char *pkt, const size_t start, int remain_pos)
+                      char *pkt, const size_t start, int remain_pos)
 {
   /* magic number that need to be set properly */
   const size_t conn_flags_pos = remain_pos + 8;
@@ -428,14 +428,13 @@
 
   if(rlen < nbytes) {
     unsigned char readbuf[1024];
-    ssize_t nread;
+    size_t nread;
 
     DEBUGASSERT(nbytes - rlen < sizeof(readbuf));
     result = Curl_xfer_recv(data, (char *)readbuf, nbytes - rlen, &nread);
     if(result)
       return result;
-    DEBUGASSERT(nread >= 0);
-    if(curlx_dyn_addn(&mq->recvbuf, readbuf, (size_t)nread))
+    if(curlx_dyn_addn(&mq->recvbuf, readbuf, nread))
       return CURLE_OUT_OF_MEMORY;
     rlen = curlx_dyn_len(&mq->recvbuf);
   }
@@ -703,7 +702,7 @@
 {
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
-  ssize_t nread;
+  size_t nread;
   size_t remlen;
   struct mqtt_conn *mqtt = Curl_conn_meta_get(conn, CURL_META_MQTT_CONN);
   struct MQTT *mq = Curl_meta_get(data, CURL_META_MQTT_EASY);
@@ -868,7 +867,7 @@
 {
   struct MQTT *mq = Curl_meta_get(data, CURL_META_MQTT_EASY);
   CURLcode result = CURLE_OK;
-  ssize_t nread;
+  size_t nread;
   unsigned char recvbyte;
   struct mqtt_conn *mqtt = Curl_conn_meta_get(data->conn, CURL_META_MQTT_CONN);
 
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 64eb1ae..b3a7938 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -42,6 +42,7 @@
 #include "http.h"
 #include "select.h"
 #include "curlx/warnless.h"
+#include "curlx/wait.h"
 #include "speedcheck.h"
 #include "conncache.h"
 #include "multihandle.h"
@@ -234,6 +235,7 @@
   Curl_multi_ev_init(multi, ev_hashsize);
   Curl_uint_tbl_init(&multi->xfers, NULL);
   Curl_uint_bset_init(&multi->process);
+  Curl_uint_bset_init(&multi->dirty);
   Curl_uint_bset_init(&multi->pending);
   Curl_uint_bset_init(&multi->msgsent);
   Curl_hash_init(&multi->proto_hash, 23,
@@ -246,6 +248,7 @@
 
   if(Curl_uint_bset_resize(&multi->process, xfer_table_size) ||
      Curl_uint_bset_resize(&multi->pending, xfer_table_size) ||
+     Curl_uint_bset_resize(&multi->dirty, xfer_table_size) ||
      Curl_uint_bset_resize(&multi->msgsent, xfer_table_size) ||
      Curl_uint_tbl_resize(&multi->xfers, xfer_table_size))
     goto error;
@@ -268,21 +271,23 @@
 
   Curl_cpool_init(&multi->cpool, multi->admin, NULL, chashsize);
 
+#ifdef USE_SSL
   if(Curl_ssl_scache_create(sesssize, 2, &multi->ssl_scache))
     goto error;
+#else
+  (void)sesssize;
+#endif
 
 #ifdef USE_WINSOCK
   multi->wsa_event = WSACreateEvent();
   if(multi->wsa_event == WSA_INVALID_EVENT)
     goto error;
-#else
-#ifdef ENABLE_WAKEUP
+#elif defined(ENABLE_WAKEUP)
   if(wakeup_create(multi->wakeup_pair, TRUE) < 0) {
     multi->wakeup_pair[0] = CURL_SOCKET_BAD;
     multi->wakeup_pair[1] = CURL_SOCKET_BAD;
   }
 #endif
-#endif
 
   return multi;
 
@@ -293,13 +298,16 @@
   Curl_dnscache_destroy(&multi->dnscache);
   Curl_cpool_destroy(&multi->cpool);
   Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
+#ifdef USE_SSL
   Curl_ssl_scache_destroy(multi->ssl_scache);
+#endif
   if(multi->admin) {
     multi->admin->multi = NULL;
     Curl_close(&multi->admin);
   }
 
   Curl_uint_bset_destroy(&multi->process);
+  Curl_uint_bset_destroy(&multi->dirty);
   Curl_uint_bset_destroy(&multi->pending);
   Curl_uint_bset_destroy(&multi->msgsent);
   Curl_uint_tbl_destroy(&multi->xfers);
@@ -335,34 +343,57 @@
 static CURLMcode multi_xfers_add(struct Curl_multi *multi,
                                  struct Curl_easy *data)
 {
-  /* We want `multi->xfers` to have "sufficient" free rows, so that we do
-   * have to reuse the `mid` from a just removed easy right away.
-   * Since uint_tbl and uint_bset is quite memory efficient,
-   * regard less than 25% free as insufficient.
-   * (for low capacities, e.g. multi_easy, 4 or less). */
   unsigned int capacity = Curl_uint_tbl_capacity(&multi->xfers);
-  unsigned int unused = capacity - Curl_uint_tbl_count(&multi->xfers);
-  unsigned int min_unused = CURLMAX(capacity >> 2, 4);
+  unsigned int new_size = 0;
+  /* Prepare to make this into a CURLMOPT_MAX_TRANSFERS, because some
+   * applications may want to prevent a run-away of their memory use. */
+  /* UINT_MAX is our "invalid" id, do not let the table grow up to that. */
+  const unsigned int max_capacity = UINT_MAX - 1;
 
-  if(unused <= min_unused) {
-     /* make it a 64 multiple, since our bitsets frow by that and
-      * small (easy_multi) grows to at least 64 on first resize. */
-    unsigned int newsize = (((capacity + min_unused) + 63) / 64) * 64;
-    DEBUGASSERT(newsize > capacity);
+  if(capacity < max_capacity) {
+    /* We want `multi->xfers` to have "sufficient" free rows, so that we do
+     * have to reuse the `mid` from a just removed easy right away.
+     * Since uint_tbl and uint_bset are quite memory efficient,
+     * regard less than 25% free as insufficient.
+     * (for low capacities, e.g. multi_easy, 4 or less). */
+    unsigned int used = Curl_uint_tbl_count(&multi->xfers);
+    unsigned int unused = capacity - used;
+    unsigned int min_unused = CURLMAX(capacity >> 2, 4);
+    if(unused <= min_unused) {
+      /* Make sure the uint arithmetic here works on the corner
+       * cases where we are close to max_capacity or UINT_MAX */
+      if((min_unused >= max_capacity) ||
+         ((max_capacity - min_unused) <= capacity) ||
+         ((UINT_MAX - min_unused - 63) <= capacity)) {
+        new_size = max_capacity; /* can not be larger than this */
+      }
+      else {
+         /* make it a 64 multiple, since our bitsets frow by that and
+          * small (easy_multi) grows to at least 64 on first resize. */
+        new_size = (((used + min_unused) + 63) / 64) * 64;
+      }
+    }
+  }
+
+  if(new_size > capacity) {
     /* Grow the bitsets first. Should one fail, we do not need
      * to downsize the already resized ones. The sets continue
      * to work properly when larger than the table, but not
      * the other way around. */
-    if(Curl_uint_bset_resize(&multi->process, newsize) ||
-       Curl_uint_bset_resize(&multi->pending, newsize) ||
-       Curl_uint_bset_resize(&multi->msgsent, newsize) ||
-       Curl_uint_tbl_resize(&multi->xfers, newsize))
+    CURL_TRC_M(data, "increasing xfer table size to %u", new_size);
+    if(Curl_uint_bset_resize(&multi->process, new_size) ||
+       Curl_uint_bset_resize(&multi->dirty, new_size) ||
+       Curl_uint_bset_resize(&multi->pending, new_size) ||
+       Curl_uint_bset_resize(&multi->msgsent, new_size) ||
+       Curl_uint_tbl_resize(&multi->xfers, new_size))
       return CURLM_OUT_OF_MEMORY;
-    CURL_TRC_M(data, "increased xfer table size to %u", newsize);
   }
-  /* Insert the easy into the table now that MUST have room for it */
+
+  /* Insert the easy into the table now */
   if(!Curl_uint_tbl_add(&multi->xfers, data, &data->mid)) {
-    DEBUGASSERT(0);
+    /* MUST only happen when table is full */
+    DEBUGASSERT(Curl_uint_tbl_capacity(&multi->xfers) <=
+                Curl_uint_tbl_count(&multi->xfers));
     return CURLM_OUT_OF_MEMORY;
   }
   return CURLM_OK;
@@ -400,6 +431,7 @@
       return CURLM_ABORTED_BY_CALLBACK;
     multi->dead = FALSE;
     Curl_uint_bset_clear(&multi->process);
+    Curl_uint_bset_clear(&multi->dirty);
     Curl_uint_bset_clear(&multi->pending);
     Curl_uint_bset_clear(&multi->msgsent);
   }
@@ -589,7 +621,7 @@
                                                 after an error was detected */
                            bool premature)
 {
-  CURLcode result, r2;
+  CURLcode result;
   struct connectdata *conn = data->conn;
   struct multi_done_ctx mdctx;
 
@@ -638,9 +670,7 @@
   }
 
   /* Make sure that transfer client writes are really done now. */
-  r2 = Curl_xfer_write_done(data, premature);
-  if(r2 && !result)
-    result = r2;
+  result = Curl_1st_err(result, Curl_xfer_write_done(data, premature));
 
   /* Inform connection filters that this transfer is done */
   Curl_conn_ev_data_done(data, premature);
@@ -794,6 +824,7 @@
   DEBUGASSERT(Curl_uint_tbl_contains(&multi->xfers, mid));
   Curl_uint_tbl_remove(&multi->xfers, mid);
   Curl_uint_bset_remove(&multi->process, mid);
+  Curl_uint_bset_remove(&multi->dirty, mid);
   Curl_uint_bset_remove(&multi->pending, mid);
   Curl_uint_bset_remove(&multi->msgsent, mid);
   data->multi = NULL;
@@ -1038,11 +1069,25 @@
     break;
   }
 
+
+  /* Unblocked and waiting to receive with buffered input.
+   * Make transfer run again at next opportunity. */
+  if(!Curl_xfer_is_blocked(data) &&
+     ((Curl_pollset_want_read(data, ps, data->conn->sock[FIRSTSOCKET]) &&
+       Curl_conn_data_pending(data, FIRSTSOCKET)) ||
+      (Curl_pollset_want_read(data, ps, data->conn->sock[SECONDARYSOCKET]) &&
+       Curl_conn_data_pending(data, SECONDARYSOCKET)))) {
+    CURL_TRC_M(data, "%s pollset[] has POLLIN, but there is still "
+               "buffered input to consume -> mark as dirty", caller);
+    Curl_multi_mark_dirty(data);
+  }
+
   switch(ps->num) {
     case 0:
       CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)",
                  caller, Curl_llist_count(&data->state.timeoutlist),
-                 Curl_creader_is_paused(data), Curl_cwriter_is_paused(data));
+                 Curl_xfer_send_is_paused(data),
+                 Curl_xfer_recv_is_paused(data));
       break;
     case 1:
       CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu",
@@ -1166,6 +1211,7 @@
       if(!data) {
         DEBUGASSERT(0);
         Curl_uint_bset_remove(&multi->process, mid);
+        Curl_uint_bset_remove(&multi->dirty, mid);
         continue;
       }
       Curl_multi_getsock(data, &ps, "curl_multi_waitfds");
@@ -1218,6 +1264,7 @@
   struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
   struct curl_pollfds cpfds;
   unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */
+  struct Curl_easy *data = NULL;
   CURLMcode result = CURLM_OK;
   unsigned int mid;
 
@@ -1243,11 +1290,12 @@
   /* Add the curl handles to our pollfds first */
   if(Curl_uint_bset_first(&multi->process, &mid)) {
     do {
-      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
       struct easy_pollset ps;
+      data = Curl_multi_get_easy(multi, mid);
       if(!data) {
         DEBUGASSERT(0);
         Curl_uint_bset_remove(&multi->process, mid);
+        Curl_uint_bset_remove(&multi->dirty, mid);
         continue;
       }
       Curl_multi_getsock(data, &ps, "multi_wait");
@@ -1320,6 +1368,9 @@
   if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
     timeout_ms = (int)timeout_internal;
 
+  if(data)
+    CURL_TRC_M(data, "multi_wait(fds=%d, timeout=%d) tinternal=%ld",
+               cpfds.n, timeout_ms, timeout_internal);
 #if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
   if(cpfds.n || use_wakeup) {
 #else
@@ -1441,7 +1492,7 @@
          timeout */
       else if(sleep_ms < 0)
         sleep_ms = timeout_ms;
-      Curl_wait_ms(sleep_ms);
+      curlx_wait_ms(sleep_ms);
     }
   }
 
@@ -1946,12 +1997,6 @@
       }
     }
   }
-  else if(data->state.select_bits && !Curl_xfer_is_blocked(data)) {
-    /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer does
-       not get stuck on this transfer at the expense of other concurrent
-       transfers */
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
-  }
   free(newurl);
   *resultp = result;
   return rc;
@@ -2215,6 +2260,7 @@
     multistate(data, MSTATE_PENDING);
     /* move from process to pending set */
     Curl_uint_bset_remove(&multi->process, data->mid);
+    Curl_uint_bset_remove(&multi->dirty, data->mid);
     Curl_uint_bset_add(&multi->pending, data->mid);
     *resultp = CURLE_OK;
     return rc;
@@ -2276,6 +2322,10 @@
 
   multi_warn_debug(multi, data);
 
+  /* transfer runs now, clear the dirty bit. This may be set
+   * again during processing, triggering a re-run later. */
+  Curl_uint_bset_remove(&multi->dirty, data->mid);
+
   do {
     /* A "stream" here is a logical stream if the protocol can handle that
        (HTTP/2), or the full connection for older protocols */
@@ -2642,6 +2692,7 @@
 
       /* remove from the other sets, add to msgsent */
       Curl_uint_bset_remove(&multi->process, data->mid);
+      Curl_uint_bset_remove(&multi->dirty, data->mid);
       Curl_uint_bset_remove(&multi->pending, data->mid);
       Curl_uint_bset_add(&multi->msgsent, data->mid);
       --multi->xfers_alive;
@@ -2679,6 +2730,7 @@
       if(!data) {
         DEBUGASSERT(0);
         Curl_uint_bset_remove(&multi->process, mid);
+        Curl_uint_bset_remove(&multi->dirty, mid);
         continue;
       }
       if(data != multi->admin) {
@@ -2757,7 +2809,7 @@
 #ifdef DEBUGBUILD
         if(mid != data->mid) {
           CURL_TRC_M(data, "multi_cleanup: still present with mid=%u, "
-                  "but unexpected data->mid=%u\n", mid, data->mid);
+                     "but unexpected data->mid=%u\n", mid, data->mid);
           DEBUGASSERT(0);
         }
 #endif
@@ -2798,7 +2850,9 @@
     Curl_hash_destroy(&multi->proto_hash);
     Curl_dnscache_destroy(&multi->dnscache);
     Curl_psl_destroy(&multi->psl);
+#ifdef USE_SSL
     Curl_ssl_scache_destroy(multi->ssl_scache);
+#endif
 
 #ifdef USE_WINSOCK
     WSACloseEvent(multi->wsa_event);
@@ -2819,6 +2873,7 @@
     }
 #endif
     Curl_uint_bset_destroy(&multi->process);
+    Curl_uint_bset_destroy(&multi->dirty);
     Curl_uint_bset_destroy(&multi->pending);
     Curl_uint_bset_destroy(&multi->msgsent);
     Curl_uint_tbl_destroy(&multi->xfers);
@@ -2942,12 +2997,11 @@
   bool run_cpool;
 };
 
-static CURLMcode multi_run_expired(struct multi_run_ctx *mrc)
+static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc)
 {
   struct Curl_multi *multi = mrc->multi;
   struct Curl_easy *data = NULL;
   struct Curl_tree *t = NULL;
-  CURLMcode result = CURLM_OK;
 
   /*
    * The loop following here will go on as long as there are expire-times left
@@ -2959,33 +3013,64 @@
        extracts a matching node if there is one */
     multi->timetree = Curl_splaygetbest(mrc->now, multi->timetree, &t);
     if(!t)
-      goto out;
+      return;
 
     data = Curl_splayget(t); /* assign this for next loop */
     if(!data)
       continue;
 
     (void)add_next_timeout(mrc->now, multi, data);
-    if(data == multi->admin) {
-      mrc->run_cpool = TRUE;
-      continue;
-    }
+    Curl_multi_mark_dirty(data);
+  }
+}
 
-    mrc->run_xfers++;
-    sigpipe_apply(data, &mrc->pipe_st);
-    result = multi_runsingle(multi, &mrc->now, data);
+static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc)
+{
+  struct Curl_multi *multi = mrc->multi;
+  CURLMcode result = CURLM_OK;
+  unsigned int mid;
 
-    if(CURLM_OK >= result) {
-      /* reassess event handling of data */
-      result = Curl_multi_ev_assess_xfer(multi, data);
-      if(result)
-        goto out;
+  if(Curl_uint_bset_first(&multi->dirty, &mid)) {
+    do {
+      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
+      if(data) {
+        CURL_TRC_M(data, "multi_run_dirty");
+
+        if(data == multi->admin) {
+          Curl_uint_bset_remove(&multi->dirty, mid);
+          mrc->run_cpool = TRUE;
+          continue;
+        }
+        else if(!Curl_uint_bset_contains(&multi->process, mid)) {
+          /* We are no longer processing this transfer */
+          Curl_uint_bset_remove(&multi->dirty, mid);
+          continue;
+        }
+
+        mrc->run_xfers++;
+        sigpipe_apply(data, &mrc->pipe_st);
+        /* runsingle() clears the dirty mid */
+        result = multi_runsingle(multi, &mrc->now, data);
+
+        if(CURLM_OK >= result) {
+          /* reassess event handling of data */
+          result = Curl_multi_ev_assess_xfer(multi, data);
+          if(result)
+            goto out;
+        }
+      }
+      else {
+        CURL_TRC_M(multi->admin, "multi_run_dirty, %u no longer found", mid);
+        Curl_uint_bset_remove(&multi->dirty, mid);
+      }
     }
+    while(Curl_uint_bset_next(&multi->dirty, mid, &mid));
   }
 
 out:
   return result;
 }
+
 static CURLMcode multi_socket(struct Curl_multi *multi,
                               bool checkall,
                               curl_socket_t s,
@@ -3014,7 +3099,8 @@
   }
 
   if(s != CURL_SOCKET_TIMEOUT) {
-    Curl_multi_ev_expire_xfers(multi, s, &mrc.now, &mrc.run_cpool);
+    /* Mark all transfers of that socket as dirty */
+    Curl_multi_ev_dirty_xfers(multi, s, &mrc.run_cpool);
   }
   else {
     /* Asked to run due to time-out. Clear the 'last_expire_ts' variable to
@@ -3026,7 +3112,8 @@
     mrc.run_cpool = TRUE;
   }
 
-  result = multi_run_expired(&mrc);
+  multi_mark_expired_as_dirty(&mrc);
+  result = multi_run_dirty(&mrc);
   if(result)
     goto out;
 
@@ -3037,7 +3124,8 @@
      * Do that only once or it might be unfair to transfers on other
      * sockets. */
     mrc.now = curlx_now();
-    result = multi_run_expired(&mrc);
+    multi_mark_expired_as_dirty(&mrc);
+    result = multi_run_dirty(&mrc);
   }
 
 out:
@@ -3165,6 +3253,29 @@
   return multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
 }
 
+
+static bool multi_has_dirties(struct Curl_multi *multi)
+{
+  unsigned int mid;
+  if(Curl_uint_bset_first(&multi->dirty, &mid)) {
+    do {
+      struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
+      if(data) {
+        if(Curl_uint_bset_contains(&multi->process, mid))
+          return TRUE;
+        /* We are no longer processing this transfer */
+        Curl_uint_bset_remove(&multi->dirty, mid);
+      }
+      else {
+        CURL_TRC_M(multi->admin, "dirty transfer %u no longer found", mid);
+        Curl_uint_bset_remove(&multi->dirty, mid);
+      }
+    }
+    while(Curl_uint_bset_next(&multi->dirty, mid, &mid));
+  }
+  return FALSE;
+}
+
 static CURLMcode multi_timeout(struct Curl_multi *multi,
                                struct curltime *expire_time,
                                long *timeout_ms)
@@ -3176,7 +3287,12 @@
     return CURLM_OK;
   }
 
-  if(multi->timetree) {
+  if(multi_has_dirties(multi)) {
+    *expire_time = curlx_now();
+    *timeout_ms = 0;
+    return CURLM_OK;
+  }
+  else if(multi->timetree) {
     /* we have a tree of expire times */
     struct curltime now = curlx_now();
 
@@ -3197,6 +3313,10 @@
       *timeout_ms = (long)diff;
     }
     else {
+      if(multi->timetree) {
+        struct Curl_easy *data = Curl_splayget(multi->timetree);
+        CURL_TRC_M(data, "multi_timeout() says this has expired");
+      }
       /* 0 means immediately */
       *timeout_ms = 0;
     }
@@ -3420,6 +3540,9 @@
   Curl_splayset(&data->state.timenode, data);
   multi->timetree = Curl_splayinsert(*curr_expire, multi->timetree,
                                      &data->state.timenode);
+  if(data->id >= 0)
+    CURL_TRC_M(data, "set expire[%d] in %" FMT_TIMEDIFF_T "ns",
+               id, curlx_timediff_us(set, *nowp));
 }
 
 /*
@@ -3763,9 +3886,15 @@
   return multi->xfers_alive;
 }
 
+void Curl_multi_mark_dirty(struct Curl_easy *data)
+{
+  if(data->multi && data->mid != UINT_MAX)
+    Curl_uint_bset_add(&data->multi->dirty, data->mid);
+}
+
 #ifdef DEBUGBUILD
 static void multi_xfer_dump(struct Curl_multi *multi, unsigned int mid,
-                             void *entry)
+                            void *entry)
 {
   struct Curl_easy *data = entry;
 
diff --git a/Utilities/cmcurl/lib/multi_ev.c b/Utilities/cmcurl/lib/multi_ev.c
index 21d2867..0b4c472 100644
--- a/Utilities/cmcurl/lib/multi_ev.c
+++ b/Utilities/cmcurl/lib/multi_ev.c
@@ -563,10 +563,9 @@
   return CURLM_OK;
 }
 
-void Curl_multi_ev_expire_xfers(struct Curl_multi *multi,
-                                curl_socket_t s,
-                                const struct curltime *nowp,
-                                bool *run_cpool)
+void Curl_multi_ev_dirty_xfers(struct Curl_multi *multi,
+                               curl_socket_t s,
+                               bool *run_cpool)
 {
   struct mev_sh_entry *entry;
 
@@ -586,9 +585,11 @@
       do {
         data = Curl_multi_get_easy(multi, mid);
         if(data) {
-          /* Expire with out current now, so we will get it below when
-           * asking the splaytree for expired transfers. */
-          Curl_expire_ex(data, nowp, 0, EXPIRE_RUN_NOW);
+          Curl_multi_mark_dirty(data);
+        }
+        else {
+          CURL_TRC_M(multi->admin, "socket transfer %u no longer found", mid);
+          Curl_uint_spbset_remove(&entry->xfers, mid);
         }
       }
       while(Curl_uint_spbset_next(&entry->xfers, mid, &mid));
diff --git a/Utilities/cmcurl/lib/multi_ev.h b/Utilities/cmcurl/lib/multi_ev.h
index 06be842..20c1aea 100644
--- a/Utilities/cmcurl/lib/multi_ev.h
+++ b/Utilities/cmcurl/lib/multi_ev.h
@@ -61,11 +61,10 @@
                                     struct Curl_easy *data,
                                     struct connectdata *conn);
 
-/* Expire all transfers tied to the given socket */
-void Curl_multi_ev_expire_xfers(struct Curl_multi *multi,
-                                curl_socket_t s,
-                                const struct curltime *nowp,
-                                bool *run_cpool);
+/* Mark all transfers tied to the given socket as dirty */
+void Curl_multi_ev_dirty_xfers(struct Curl_multi *multi,
+                               curl_socket_t s,
+                               bool *run_cpool);
 
 /* Socket will be closed, forget anything we know about it. */
 void Curl_multi_ev_socket_done(struct Curl_multi *multi,
diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
index 04db02f..4bf2dd8 100644
--- a/Utilities/cmcurl/lib/multihandle.h
+++ b/Utilities/cmcurl/lib/multihandle.h
@@ -98,6 +98,7 @@
   struct uint_tbl xfers; /* transfers added to this multi */
   /* Each transfer's mid may be present in at most one of these */
   struct uint_bset process; /* transfer being processed */
+  struct uint_bset dirty; /* transfer to be run NOW, e.g. ASAP. */
   struct uint_bset pending; /* transfers in waiting (conn limit etc.) */
   struct uint_bset msgsent; /* transfers done with message for application */
 
diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h
index eae634a..1ba0d0f 100644
--- a/Utilities/cmcurl/lib/multiif.h
+++ b/Utilities/cmcurl/lib/multiif.h
@@ -36,7 +36,7 @@
 void Curl_expire_done(struct Curl_easy *data, expire_id id);
 CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT;
 void Curl_attach_connection(struct Curl_easy *data,
-                             struct connectdata *conn);
+                            struct connectdata *conn);
 void Curl_detach_connection(struct Curl_easy *data);
 bool Curl_multiplex_wanted(const struct Curl_multi *multi);
 void Curl_set_in_callback(struct Curl_easy *data, bool value);
@@ -106,7 +106,7 @@
  *         CURLE_AGAIN if the buffer is borrowed already.
  */
 CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
-                                   char **pbuf, size_t *pbuflen);
+                                    char **pbuf, size_t *pbuflen);
 /**
  * Release the borrowed buffer. All references into the buffer become
  * invalid after this.
@@ -173,4 +173,8 @@
 /* Get the # of transfers current in process/pending. */
 unsigned int Curl_multi_xfers_running(struct Curl_multi *multi);
 
+/* Mark a transfer as dirty, e.g. to be rerun at earliest convenience.
+ * A cheap operation, can be done many times repeatedly. */
+void Curl_multi_mark_dirty(struct Curl_easy *data);
+
 #endif /* HEADER_CURL_MULTIIF_H */
diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c
index 7df3f17..bf53fc0 100644
--- a/Utilities/cmcurl/lib/netrc.c
+++ b/Utilities/cmcurl/lib/netrc.c
@@ -229,12 +229,12 @@
 
       switch(state) {
       case NOTHING:
-        if(strcasecompare("macdef", tok))
+        if(curl_strequal("macdef", tok))
           /* Define a macro. A macro is defined with the specified name; its
              contents begin with the next .netrc line and continue until a
              null line (consecutive new-line characters) is encountered. */
           state = MACDEF;
-        else if(strcasecompare("machine", tok)) {
+        else if(curl_strequal("machine", tok)) {
           /* the next tok is the machine name, this is in itself the delimiter
              that starts the stuff entered for this machine, after this we
              need to search for 'login' and 'password'. */
@@ -246,7 +246,7 @@
           if(!specific_login)
             Curl_safefree(login);
         }
-        else if(strcasecompare("default", tok)) {
+        else if(curl_strequal("default", tok)) {
           state = HOSTVALID;
           retcode = NETRC_OK; /* we did find our host */
         }
@@ -256,7 +256,7 @@
           state = NOTHING;
         break;
       case HOSTFOUND:
-        if(strcasecompare(host, tok)) {
+        if(curl_strequal(host, tok)) {
           /* and yes, this is our host! */
           state = HOSTVALID;
           retcode = NETRC_OK; /* we did find our host */
@@ -293,11 +293,11 @@
             found |= FOUND_PASSWORD;
           keyword = NONE;
         }
-        else if(strcasecompare("login", tok))
+        else if(curl_strequal("login", tok))
           keyword = LOGIN;
-        else if(strcasecompare("password", tok))
+        else if(curl_strequal("password", tok))
           keyword = PASSWORD;
-        else if(strcasecompare("machine", tok)) {
+        else if(curl_strequal("machine", tok)) {
           /* a new machine here */
           if(found & FOUND_PASSWORD) {
             done = TRUE;
@@ -310,7 +310,7 @@
           if(!specific_login)
             Curl_safefree(login);
         }
-        else if(strcasecompare("default", tok)) {
+        else if(curl_strequal("default", tok)) {
           state = HOSTVALID;
           retcode = NETRC_OK; /* we did find our host */
           Curl_safefree(password);
diff --git a/Utilities/cmcurl/lib/noproxy.c b/Utilities/cmcurl/lib/noproxy.c
index f70f57e..306cd6d 100644
--- a/Utilities/cmcurl/lib/noproxy.c
+++ b/Utilities/cmcurl/lib/noproxy.c
@@ -26,8 +26,8 @@
 
 #ifndef CURL_DISABLE_PROXY
 
+#include <curl/curl.h>  /* for curl_strnequal() */
 #include "curlx/inet_pton.h"
-#include "strcase.h"
 #include "noproxy.h"
 #include "curlx/strparse.h"
 
@@ -205,12 +205,12 @@
           */
           if(tokenlen == namelen)
             /* case A, exact match */
-            match = strncasecompare(token, name, namelen);
+            match = curl_strnequal(token, name, namelen);
           else if(tokenlen < namelen) {
             /* case B, tailmatch domain */
             match = (name[namelen - tokenlen - 1] == '.') &&
-              strncasecompare(token, name + (namelen - tokenlen),
-                              tokenlen);
+              curl_strnequal(token, name + (namelen - tokenlen),
+                             tokenlen);
           }
           /* case C passes through, not a match */
           break;
diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
index 6343c40..e4714b5 100644
--- a/Utilities/cmcurl/lib/openldap.c
+++ b/Utilities/cmcurl/lib/openldap.c
@@ -941,7 +941,6 @@
       ldap_unbind_ext(li->ld, NULL, NULL);
       li->ld = NULL;
     }
-    Curl_sasl_cleanup(conn, li->sasl.authused);
   }
   return CURLE_OK;
 }
@@ -1048,8 +1047,8 @@
   return result;
 }
 
-static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
-                          size_t len, CURLcode *err)
+static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
+                           size_t len, size_t *pnread)
 {
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
@@ -1067,10 +1066,9 @@
   (void)len;
   (void)buf;
   (void)sockindex;
-  if(!li || !lr) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  *pnread = 0;
+  if(!li || !lr)
+    return CURLE_FAILED_INIT;
 
   rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg);
   if(rc < 0) {
@@ -1078,11 +1076,9 @@
     result = CURLE_RECV_ERROR;
   }
 
-  *err = result;
-
   /* error or timed out */
   if(!msg)
-    return -1;
+    return result;
 
   result = CURLE_OK;
 
@@ -1210,8 +1206,7 @@
   }
 
   ldap_msgfree(msg);
-  *err = result;
-  return result ? -1 : 0;
+  return result;
 }
 
 #ifdef USE_SSL
@@ -1258,15 +1253,17 @@
     if(conn) {
       struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
       CURLcode err = CURLE_RECV_ERROR;
+      size_t nread;
 
       if(!li) {
         SET_SOCKERRNO(SOCKEINVAL);
         return -1;
       }
-      ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
-      if(ret < 0 && err == CURLE_AGAIN) {
+      err = (li->recv)(data, FIRSTSOCKET, buf, len, &nread);
+      if(err == CURLE_AGAIN) {
         SET_SOCKERRNO(SOCKEWOULDBLOCK);
       }
+      ret = err ? -1 : (ber_slen_t)nread;
     }
   }
   return ret;
@@ -1281,15 +1278,17 @@
     if(conn) {
       struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
       CURLcode err = CURLE_SEND_ERROR;
+      size_t nwritten;
 
       if(!li) {
         SET_SOCKERRNO(SOCKEINVAL);
         return -1;
       }
-      ret = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &err);
-      if(ret < 0 && err == CURLE_AGAIN) {
+      err = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &nwritten);
+      if(err == CURLE_AGAIN) {
         SET_SOCKERRNO(SOCKEWOULDBLOCK);
       }
+      ret = err ? -1 : (ber_slen_t)nwritten;
     }
   }
   return ret;
diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c
index 7e0c691..65730d6 100644
--- a/Utilities/cmcurl/lib/parsedate.c
+++ b/Utilities/cmcurl/lib/parsedate.c
@@ -80,7 +80,6 @@
 #include <limits.h>
 
 #include <curl/curl.h>
-#include "strcase.h"
 #include "curlx/warnless.h"
 #include "parsedate.h"
 #include "curlx/strparse.h"
@@ -224,7 +223,7 @@
   for(i = 0; i < 7; i++) {
     size_t ilen = strlen(what[0]);
     if((ilen == len) &&
-       strncasecompare(check, what[0], len))
+       curl_strnequal(check, what[0], len))
       return i;
     what++;
   }
@@ -239,7 +238,7 @@
     return -1; /* not a month */
 
   for(i = 0; i < 12; i++) {
-    if(strncasecompare(check, what[0], 3))
+    if(curl_strnequal(check, what[0], 3))
       return i;
     what++;
   }
@@ -259,7 +258,7 @@
   for(i = 0; i < CURL_ARRAYSIZE(tz); i++) {
     size_t ilen = strlen(what->name);
     if((ilen == len) &&
-       strncasecompare(check, what->name, len))
+       curl_strnequal(check, what->name, len))
       return what->offset*60;
     what++;
   }
diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c
index c5513f6..a661a02 100644
--- a/Utilities/cmcurl/lib/pingpong.c
+++ b/Utilities/cmcurl/lib/pingpong.c
@@ -52,7 +52,7 @@
                                  struct pingpong *pp, bool disconnecting)
 {
   timediff_t timeout_ms; /* in milliseconds */
-  timediff_t response_time = (data->set.server_response_timeout) ?
+  timediff_t response_time = (data->set.server_response_timeout > 0) ?
     data->set.server_response_timeout : pp->response_time;
   struct curltime now = curlx_now();
 
@@ -65,7 +65,7 @@
      full response to arrive before we bail out */
   timeout_ms = response_time - curlx_timediff(now, pp->response);
 
-  if(data->set.timeout && !disconnecting) {
+  if((data->set.timeout > 0) && !disconnecting) {
     /* if timeout is requested, find out how much overall remains */
     timediff_t timeout2_ms = Curl_timeleft(data, &now, FALSE);
     /* pick the lowest number */
@@ -116,11 +116,15 @@
   else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET))
     /* We are receiving and there is data ready in the SSL library */
     rc = 1;
-  else
+  else {
+    DEBUGF(infof(data, "pp_statematch, select, timeout=%" FMT_TIMEDIFF_T
+           ", sendleft=%zu",
+           timeout_ms, pp->sendleft));
     rc = Curl_socket_check(pp->sendleft ? CURL_SOCKET_BAD : sock, /* reading */
                            CURL_SOCKET_BAD,
                            pp->sendleft ? sock : CURL_SOCKET_BAD, /* writing */
                            interval_ms);
+  }
 
   if(block) {
     /* if we did not wait, we do not have to spend time on this now */
@@ -266,7 +270,7 @@
                               int sockindex,
                               char *buffer,
                               size_t buflen,
-                              ssize_t *nread)
+                              size_t *nread)
 {
   CURLcode result;
 #ifdef HAVE_GSSAPI
@@ -294,7 +298,7 @@
 {
   struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
-  ssize_t gotbytes;
+  size_t gotbytes;
   char buffer[900];
 
   *code = 0; /* 0 for errors or not done */
@@ -321,7 +325,7 @@
       if(result)
         return result;
 
-      if(gotbytes <= 0) {
+      if(!gotbytes) {
         failf(data, "response reading failed (errno: %d)", SOCKERRNO);
         return CURLE_RECV_ERROR;
       }
diff --git a/Utilities/cmcurl/lib/pingpong.h b/Utilities/cmcurl/lib/pingpong.h
index 0665b83..c6d0a56 100644
--- a/Utilities/cmcurl/lib/pingpong.h
+++ b/Utilities/cmcurl/lib/pingpong.h
@@ -59,7 +59,7 @@
   struct dynbuf recvbuf;
   size_t overflow; /* number of bytes left after a final response line */
   size_t nfinal;   /* number of bytes in the final response line, which
-                      after a match is first in the receice buffer */
+                      after a match is first in the receive buffer */
 
   /* Function pointers the protocols MUST implement and provide for the
      pingpong layer to function */
diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
index aa8c2d8..514c4b8 100644
--- a/Utilities/cmcurl/lib/pop3.c
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -66,7 +66,6 @@
 #include "socks.h"
 #include "pingpong.h"
 #include "pop3.h"
-#include "strcase.h"
 #include "vtls/vtls.h"
 #include "cfilters.h"
 #include "connect.h"
@@ -285,7 +284,7 @@
 {
   size_t i;
   for(i = 0; i < CURL_ARRAYSIZE(pop3cmds); ++i) {
-    if(strncasecompare(pop3cmds[i].name, cmdline, pop3cmds[i].nlen)) {
+    if(curl_strnequal(pop3cmds[i].name, cmdline, pop3cmds[i].nlen)) {
       if(!cmdline[pop3cmds[i].nlen])
         return pop3cmds[i].multiline;
       else if(cmdline[pop3cmds[i].nlen] == ' ')
@@ -1450,7 +1449,8 @@
      bad in any way, sending quit and waiting around here will make the
      disconnect wait in vain and cause more problems than we need to. */
 
-  if(!dead_connection && conn->bits.protoconnstart) {
+  if(!dead_connection && conn->bits.protoconnstart &&
+     !Curl_pp_needs_flush(data, &pop3c->pp)) {
     if(!pop3_perform_quit(data, conn))
       (void)pop3_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */
   }
@@ -1458,9 +1458,6 @@
   /* Disconnect from the server */
   Curl_pp_disconnect(&pop3c->pp);
 
-  /* Cleanup the SASL module */
-  Curl_sasl_cleanup(conn, pop3c->sasl.authused);
-
   /* Cleanup our connection based variables */
   Curl_safefree(pop3c->apoptimestamp);
 
@@ -1593,11 +1590,11 @@
     while(*ptr && *ptr != ';')
       ptr++;
 
-    if(strncasecompare(key, "AUTH=", 5)) {
+    if(curl_strnequal(key, "AUTH=", 5)) {
       result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
                                                value, ptr - value);
 
-      if(result && strncasecompare(value, "+APOP", ptr - value)) {
+      if(result && curl_strnequal(value, "+APOP", ptr - value)) {
         pop3c->preftype = POP3_TYPE_APOP;
         pop3c->sasl.prefmech = SASL_AUTH_NONE;
         result = CURLE_OK;
diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c
index 8e6d98f..746805f 100644
--- a/Utilities/cmcurl/lib/progress.c
+++ b/Utilities/cmcurl/lib/progress.c
@@ -44,18 +44,18 @@
     strcpy(r, "--:--:--");
     return;
   }
-  h = seconds / CURL_OFF_T_C(3600);
-  if(h <= CURL_OFF_T_C(99)) {
-    curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
-    curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
+  h = seconds / 3600;
+  if(h <= 99) {
+    curl_off_t m = (seconds - (h * 3600)) / 60;
+    curl_off_t s = (seconds - (h * 3600)) - (m * 60);
     msnprintf(r, 9, "%2" FMT_OFF_T ":%02" FMT_OFF_T ":%02" FMT_OFF_T, h, m, s);
   }
   else {
     /* this equals to more than 99 hours, switch to a more suitable output
        format to fit within the limits. */
-    curl_off_t d = seconds / CURL_OFF_T_C(86400);
-    h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
-    if(d <= CURL_OFF_T_C(999))
+    curl_off_t d = seconds / 86400;
+    h = (seconds - (d * 86400)) / 3600;
+    if(d <= 999)
       msnprintf(r, 9, "%3" FMT_OFF_T "d %02" FMT_OFF_T "h", d, h);
     else
       msnprintf(r, 9, "%7" FMT_OFF_T "d", d);
@@ -67,39 +67,39 @@
    Add suffix k, M, G when suitable... */
 static char *max5data(curl_off_t bytes, char *max5)
 {
-#define ONE_KILOBYTE  CURL_OFF_T_C(1024)
-#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE)
-#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE)
-#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE)
-#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
+#define ONE_KILOBYTE (curl_off_t)1024
+#define ONE_MEGABYTE (1024 * ONE_KILOBYTE)
+#define ONE_GIGABYTE (1024 * ONE_MEGABYTE)
+#define ONE_TERABYTE (1024 * ONE_GIGABYTE)
+#define ONE_PETABYTE (1024 * ONE_TERABYTE)
 
-  if(bytes < CURL_OFF_T_C(100000))
+  if(bytes < 100000)
     msnprintf(max5, 6, "%5" FMT_OFF_T, bytes);
 
-  else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
+  else if(bytes < 10000 * ONE_KILOBYTE)
     msnprintf(max5, 6, "%4" FMT_OFF_T "k", bytes/ONE_KILOBYTE);
 
-  else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
+  else if(bytes < 100 * ONE_MEGABYTE)
     /* 'XX.XM' is good as long as we are less than 100 megs */
     msnprintf(max5, 6, "%2" FMT_OFF_T ".%0"
               FMT_OFF_T "M", bytes/ONE_MEGABYTE,
-              (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
+              (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/10) );
 
-  else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
+  else if(bytes < 10000 * ONE_MEGABYTE)
     /* 'XXXXM' is good until we are at 10000MB or above */
     msnprintf(max5, 6, "%4" FMT_OFF_T "M", bytes/ONE_MEGABYTE);
 
-  else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
+  else if(bytes < 100 * ONE_GIGABYTE)
     /* 10000 MB - 100 GB, we show it as XX.XG */
     msnprintf(max5, 6, "%2" FMT_OFF_T ".%0"
               FMT_OFF_T "G", bytes/ONE_GIGABYTE,
-              (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
+              (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/10) );
 
-  else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
+  else if(bytes < 10000 * ONE_GIGABYTE)
     /* up to 10000GB, display without decimal: XXXXG */
     msnprintf(max5, 6, "%4" FMT_OFF_T "G", bytes/ONE_GIGABYTE);
 
-  else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
+  else if(bytes < 10000 * ONE_TERABYTE)
     /* up to 10000TB, display without decimal: XXXXT */
     msnprintf(max5, 6, "%4" FMT_OFF_T "T", bytes/ONE_TERABYTE);
 
@@ -296,7 +296,7 @@
    * stay below 'limit'.
    */
   if(size < CURL_OFF_T_MAX/1000)
-    minimum = (timediff_t) (CURL_OFF_T_C(1000) * size / speed_limit);
+    minimum = (timediff_t) (1000 * size / speed_limit);
   else {
     minimum = (timediff_t) (size / speed_limit);
     if(minimum < TIMEDIFF_T_MAX/1000)
@@ -455,7 +455,7 @@
       /* Calculate the average speed the last 'span_ms' milliseconds */
       amount = p->speeder[nowindex]- p->speeder[checkindex];
 
-      if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
+      if(amount > (0xffffffff/1000))
         /* the 'amount' value is bigger than would fit in 32 bits if
            multiplied with 1000, so we use the double math for this */
         p->current_speed = (curl_off_t)
@@ -463,7 +463,7 @@
       else
         /* the 'amount' value is small enough to fit within 32 bits even
            when multiplied with 1000 */
-        p->current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
+        p->current_speed = amount * 1000/span_ms;
     }
     else
       /* the first second we use the average */
@@ -482,9 +482,9 @@
 
 static curl_off_t pgrs_est_percent(curl_off_t total, curl_off_t cur)
 {
-  if(total > CURL_OFF_T_C(10000))
-    return cur / (total/CURL_OFF_T_C(100));
-  else if(total > CURL_OFF_T_C(0))
+  if(total > 10000)
+    return cur / (total / 100);
+  else if(total > 0)
     return (cur*100) / total;
   return 0;
 }
@@ -495,7 +495,7 @@
 {
   est->secs = 0;
   est->percent = 0;
-  if(total_known && (d->speed > CURL_OFF_T_C(0))) {
+  if(total_known && (d->speed > 0)) {
     est->secs = d->total_size / d->speed;
     est->percent = pgrs_est_percent(d->total_size, d->cur_size);
   }
diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c
index c0368dd..72545e0 100644
--- a/Utilities/cmcurl/lib/rand.c
+++ b/Utilities/cmcurl/lib/rand.c
@@ -103,8 +103,8 @@
 #if !defined(USE_SSL)
 /* ---- possibly non-cryptographic version following ---- */
 static CURLcode weak_random(struct Curl_easy *data,
-                          unsigned char *entropy,
-                          size_t length) /* always 4, size of int */
+                            unsigned char *entropy,
+                            size_t length) /* always 4, size of int */
 {
   unsigned int r;
   DEBUGASSERT(length == sizeof(int));
diff --git a/Utilities/cmcurl/lib/request.c b/Utilities/cmcurl/lib/request.c
index f937a7f..0d9b23e 100644
--- a/Utilities/cmcurl/lib/request.c
+++ b/Utilities/cmcurl/lib/request.c
@@ -338,20 +338,18 @@
   return CURLE_OK;
 }
 
-static ssize_t add_from_client(void *reader_ctx,
-                               unsigned char *buf, size_t buflen,
-                               CURLcode *err)
+static CURLcode add_from_client(void *reader_ctx,
+                                unsigned char *buf, size_t buflen,
+                                size_t *pnread)
 {
   struct Curl_easy *data = reader_ctx;
-  size_t nread;
+  CURLcode result;
   bool eos;
 
-  *err = Curl_client_read(data, (char *)buf, buflen, &nread, &eos);
-  if(*err)
-    return -1;
-  if(eos)
+  result = Curl_client_read(data, (char *)buf, buflen, pnread, &eos);
+  if(!result && eos)
     data->req.eos_read = TRUE;
-  return (ssize_t)nread;
+  return result;
 }
 
 static CURLcode req_send_buffer_add(struct Curl_easy *data,
@@ -359,13 +357,12 @@
                                     size_t hds_len)
 {
   CURLcode result = CURLE_OK;
-  ssize_t n;
-  n = Curl_bufq_write(&data->req.sendbuf,
-                      (const unsigned char *)buf, blen, &result);
-  if(n < 0)
+  size_t n;
+  result = Curl_bufq_cwrite(&data->req.sendbuf, buf, blen, &n);
+  if(result)
     return result;
   /* We rely on a SOFTLIMIT on sendbuf, so it can take all data in */
-  DEBUGASSERT((size_t)n == blen);
+  DEBUGASSERT(n == blen);
   data->req.sendbuf_hds_len += hds_len;
   return CURLE_OK;
 }
@@ -435,11 +432,12 @@
   /* Fill our send buffer if more from client can be read. */
   if(!data->req.upload_aborted &&
      !data->req.eos_read &&
-     !(data->req.keepon & KEEP_SEND_PAUSE) &&
+     !Curl_xfer_send_is_paused(data) &&
      !Curl_bufq_is_full(&data->req.sendbuf)) {
-    ssize_t nread = Curl_bufq_sipn(&data->req.sendbuf, 0,
-                                   add_from_client, data, &result);
-    if(nread < 0 && result != CURLE_AGAIN)
+    size_t nread;
+    result = Curl_bufq_sipn(&data->req.sendbuf, 0,
+                            add_from_client, data, &nread);
+    if(result && result != CURLE_AGAIN)
       return result;
   }
 
diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c
index ee239b7..2353c47 100644
--- a/Utilities/cmcurl/lib/select.c
+++ b/Utilities/cmcurl/lib/select.c
@@ -36,75 +36,19 @@
 #include <unistd.h>
 #endif
 
-#ifdef MSDOS
-#include <dos.h>  /* delay() */
-#endif
-
 #include <curl/curl.h>
 
 #include "urldata.h"
 #include "connect.h"
 #include "select.h"
 #include "curlx/timediff.h"
+#include "curlx/wait.h"
 #include "curlx/warnless.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
-/*
- * Internal function used for waiting a specific amount of ms in
- * Curl_socket_check() and Curl_poll() when no file descriptor is provided to
- * wait on, just being used to delay execution. Winsock select() and poll()
- * timeout mechanisms need a valid socket descriptor in a not null file
- * descriptor set to work. Waiting indefinitely with this function is not
- * allowed, a zero or negative timeout value will return immediately. Timeout
- * resolution, accuracy, as well as maximum supported value is system
- * dependent, neither factor is a critical issue for the intended use of this
- * function in the library.
- *
- * Return values:
- *   -1 = system call error, or invalid timeout value
- *    0 = specified timeout has elapsed, or interrupted
- */
-int Curl_wait_ms(timediff_t timeout_ms)
-{
-  int r = 0;
-
-  if(!timeout_ms)
-    return 0;
-  if(timeout_ms < 0) {
-    SET_SOCKERRNO(SOCKEINVAL);
-    return -1;
-  }
-#if defined(MSDOS)
-  delay((unsigned int)timeout_ms);
-#elif defined(_WIN32)
-  /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
-#if TIMEDIFF_T_MAX >= ULONG_MAX
-  if(timeout_ms >= ULONG_MAX)
-    timeout_ms = ULONG_MAX-1;
-    /* do not use ULONG_MAX, because that is equal to INFINITE */
-#endif
-  Sleep((DWORD)timeout_ms);
-#else
-  /* avoid using poll() for this since it behaves incorrectly with no sockets
-     on Apple operating systems */
-  {
-    struct timeval pending_tv;
-    r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
-  }
-#endif /* _WIN32 */
-  if(r) {
-    if((r == -1) && (SOCKERRNO == SOCKEINTR))
-      /* make EINTR from select or poll not a "lethal" error */
-      r = 0;
-    else
-      r = -1;
-  }
-  return r;
-}
-
 #ifndef HAVE_POLL
 /*
  * This is a wrapper around select() to aid in Windows compatibility. A
@@ -132,7 +76,7 @@
      (!fds_write || fds_write->fd_count == 0) &&
      (!fds_err || fds_err->fd_count == 0)) {
     /* no sockets, just wait */
-    return Curl_wait_ms(timeout_ms);
+    return curlx_wait_ms(timeout_ms);
   }
 #endif
 
@@ -194,7 +138,7 @@
   if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
      (writefd == CURL_SOCKET_BAD)) {
     /* no sockets, just wait */
-    return Curl_wait_ms(timeout_ms);
+    return curlx_wait_ms(timeout_ms);
   }
 
   /* Avoid initial timestamp, avoid curlx_now() call, when elapsed
@@ -289,7 +233,7 @@
   }
   if(fds_none) {
     /* no sockets, just wait */
-    return Curl_wait_ms(timeout_ms);
+    return curlx_wait_ms(timeout_ms);
   }
 
   /* Avoid initial timestamp, avoid curlx_now() call, when elapsed
diff --git a/Utilities/cmcurl/lib/select.h b/Utilities/cmcurl/lib/select.h
index 10968fa..e9cec60 100644
--- a/Utilities/cmcurl/lib/select.h
+++ b/Utilities/cmcurl/lib/select.h
@@ -82,7 +82,6 @@
   Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z)
 
 int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms);
-int Curl_wait_ms(timediff_t timeout_ms);
 
 /*
    With Winsock the valid range is [0..INVALID_SOCKET-1] according to
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
index feb4598..339a877 100644
--- a/Utilities/cmcurl/lib/sendf.c
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -38,6 +38,7 @@
 
 #include "urldata.h"
 #include "sendf.h"
+#include "transfer.h"
 #include "cfilters.h"
 #include "connect.h"
 #include "content_encoding.h"
@@ -176,8 +177,8 @@
 
 /* Write data using an unencoding writer stack. */
 CURLcode Curl_cwriter_write(struct Curl_easy *data,
-                             struct Curl_cwriter *writer, int type,
-                             const char *buf, size_t nbytes)
+                            struct Curl_cwriter *writer, int type,
+                            const char *buf, size_t nbytes)
 {
   if(!writer)
     return CURLE_WRITE_ERROR;
@@ -376,9 +377,9 @@
 
 /* Create an unencoding writer stage using the given handler. */
 CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
-                                   struct Curl_easy *data,
-                                   const struct Curl_cwtype *cwt,
-                                   Curl_cwriter_phase phase)
+                             struct Curl_easy *data,
+                             const struct Curl_cwtype *cwt,
+                             Curl_cwriter_phase phase)
 {
   struct Curl_cwriter *writer = NULL;
   CURLcode result = CURLE_OUT_OF_MEMORY;
@@ -403,7 +404,7 @@
 }
 
 void Curl_cwriter_free(struct Curl_easy *data,
-                             struct Curl_cwriter *writer)
+                       struct Curl_cwriter *writer)
 {
   if(writer) {
     writer->cwt->do_close(data, writer);
@@ -660,6 +661,7 @@
                            size_t *pnread, bool *peos)
 {
   struct cr_in_ctx *ctx = reader->ctx;
+  CURLcode result = CURLE_OK;
   size_t nread;
 
   ctx->is_paused = FALSE;
@@ -697,7 +699,8 @@
       failf(data, "client read function EOF fail, "
             "only %"FMT_OFF_T"/%"FMT_OFF_T " of needed bytes read",
             ctx->read_len, ctx->total_len);
-      return CURLE_READ_ERROR;
+      result = CURLE_READ_ERROR;
+      break;
     }
     *pnread = 0;
     *peos = TRUE;
@@ -710,7 +713,8 @@
     *peos = FALSE;
     ctx->errored = TRUE;
     ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
-    return CURLE_ABORTED_BY_CALLBACK;
+    result = CURLE_ABORTED_BY_CALLBACK;
+    break;
 
   case CURL_READFUNC_PAUSE:
     if(data->conn->handler->flags & PROTOPT_NONETWORK) {
@@ -718,14 +722,15 @@
          actually only FILE:// just now, and it cannot pause since the transfer
          is not done using the "normal" procedure. */
       failf(data, "Read callback asked for PAUSE when not supported");
-      return CURLE_READ_ERROR;
+      result = CURLE_READ_ERROR;
+      break;
     }
     /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
     CURL_TRC_READ(data, "cr_in_read, callback returned CURL_READFUNC_PAUSE");
     ctx->is_paused = TRUE;
-    data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
     *pnread = 0;
     *peos = FALSE;
+    result = Curl_xfer_pause_send(data, TRUE);
     break; /* nothing was read */
 
   default:
@@ -736,7 +741,8 @@
       *peos = FALSE;
       ctx->errored = TRUE;
       ctx->error_result = CURLE_READ_ERROR;
-      return CURLE_READ_ERROR;
+      result = CURLE_READ_ERROR;
+      break;
     }
     ctx->read_len += nread;
     if(ctx->total_len >= 0)
@@ -747,9 +753,9 @@
   }
   CURL_TRC_READ(data, "cr_in_read(len=%zu, total=%"FMT_OFF_T
                 ", read=%"FMT_OFF_T") -> %d, nread=%zu, eos=%d",
-                blen, ctx->total_len, ctx->read_len, CURLE_OK,
+                blen, ctx->total_len, ctx->read_len, result,
                 *pnread, *peos);
-  return CURLE_OK;
+  return result;
 }
 
 static bool cr_in_needs_rewind(struct Curl_easy *data,
@@ -1362,7 +1368,7 @@
 };
 
 CURLcode Curl_creader_set_buf(struct Curl_easy *data,
-                               const char *buf, size_t blen)
+                              const char *buf, size_t blen)
 {
   CURLcode result;
   struct Curl_creader *r;
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index d5ddf6d..1380c33 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/setopt.c
@@ -60,6 +60,35 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+
+static CURLcode setopt_set_timeout_sec(timediff_t *ptimeout_ms, long secs)
+{
+  if(secs < 0)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+#if LONG_MAX > (TIMEDIFF_T_MAX/1000)
+  if(secs > (TIMEDIFF_T_MAX/1000)) {
+    *ptimeout_ms = TIMEDIFF_T_MAX;
+    return CURLE_OK;
+  }
+#endif
+  *ptimeout_ms = (timediff_t)secs * 1000;
+  return CURLE_OK;
+}
+
+static CURLcode setopt_set_timeout_ms(timediff_t *ptimeout_ms, long ms)
+{
+  if(ms < 0)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+#if LONG_MAX > TIMEDIFF_T_MAX
+  if(ms > TIMEDIFF_T_MAX) {
+    *ptimeout_ms = TIMEDIFF_T_MAX;
+    return CURLE_OK;
+  }
+#endif
+  *ptimeout_ms = (timediff_t)ms;
+  return CURLE_OK;
+}
+
 CURLcode Curl_setstropt(char **charp, const char *s)
 {
   /* Release the previous storage at `charp' and replace by a dynamic storage
@@ -211,6 +240,7 @@
   return CURLE_OK;
 }
 
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_PROXY)
 static CURLcode httpauth(struct Curl_easy *data, bool proxy,
                          unsigned long auth)
 {
@@ -255,6 +285,7 @@
     data->set.httpauth = auth;
   return CURLE_OK;
 }
+#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_PROXY */
 
 #ifndef CURL_DISABLE_HTTP
 static CURLcode setopt_HTTP_VERSION(struct Curl_easy *data, long arg)
@@ -526,21 +557,15 @@
      * Option that specifies how quickly a server response must be obtained
      * before it is considered failure. For pingpong protocols.
      */
-    if((arg >= 0) && (arg <= (INT_MAX/1000)))
-      data->set.server_response_timeout = (unsigned int)arg * 1000;
-    else
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
+    return setopt_set_timeout_sec(&data->set.server_response_timeout, arg);
+
   case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS:
     /*
      * Option that specifies how quickly a server response must be obtained
      * before it is considered failure. For pingpong protocols.
      */
-    if((arg >= 0) && (arg <= INT_MAX))
-      data->set.server_response_timeout = (unsigned int)arg;
-    else
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
+    return setopt_set_timeout_ms(&data->set.server_response_timeout, arg);
+
 #ifndef CURL_DISABLE_TFTP
   case CURLOPT_TFTP_NO_OPTIONS:
     /*
@@ -883,10 +908,8 @@
     /*
      * The maximum time for curl to wait for FTP server connect
      */
-    if(uarg > UINT_MAX)
-      uarg = UINT_MAX;
-    data->set.accepttimeout = (unsigned int)uarg;
-    break;
+    return setopt_set_timeout_ms(&data->set.accepttimeout, arg);
+
   case CURLOPT_WILDCARDMATCH:
     data->set.wildcard_enabled = enabled;
     break;
@@ -943,33 +966,19 @@
      * The maximum time you allow curl to use for a single transfer
      * operation.
      */
-    if((arg >= 0) && (arg <= (INT_MAX/1000)))
-      data->set.timeout = (unsigned int)arg * 1000;
-    else
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
+    return setopt_set_timeout_sec(&data->set.timeout, arg);
 
   case CURLOPT_TIMEOUT_MS:
-    if(uarg > UINT_MAX)
-      uarg = UINT_MAX;
-    data->set.timeout = (unsigned int)uarg;
-    break;
+    return setopt_set_timeout_ms(&data->set.timeout, arg);
 
   case CURLOPT_CONNECTTIMEOUT:
     /*
      * The maximum time you allow curl to use to connect.
      */
-    if((arg >= 0) && (arg <= (INT_MAX/1000)))
-      data->set.connecttimeout = (unsigned int)arg * 1000;
-    else
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
+    return setopt_set_timeout_sec(&data->set.connecttimeout, arg);
 
   case CURLOPT_CONNECTTIMEOUT_MS:
-    if(uarg > UINT_MAX)
-      uarg = UINT_MAX;
-    data->set.connecttimeout = (unsigned int)uarg;
-    break;
+    return setopt_set_timeout_ms(&data->set.connecttimeout, arg);
 
   case CURLOPT_RESUME_FROM:
     /*
@@ -1074,13 +1083,9 @@
     break;
   case CURLOPT_SSL_FALSESTART:
     /*
-     * Enable TLS false start.
+     * No TLS backends support false start anymore.
      */
-    if(!Curl_ssl_false_start())
-      return CURLE_NOT_BUILT_IN;
-
-    data->set.ssl.falsestart = enabled;
-    break;
+    return CURLE_NOT_BUILT_IN;
   case CURLOPT_CERTINFO:
 #ifdef USE_SSL
     if(Curl_ssl_supports(data, SSLSUPP_CERTINFO))
@@ -1347,10 +1352,8 @@
     data->set.suppress_connect_headers = enabled;
     break;
   case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS:
-    if(uarg > UINT_MAX)
-      uarg = UINT_MAX;
-    data->set.happy_eyeballs_timeout = (unsigned int)uarg;
-    break;
+    return setopt_set_timeout_ms(&data->set.happy_eyeballs_timeout, arg);
+
 #ifndef CURL_DISABLE_SHUFFLE_DNS
   case CURLOPT_DNS_SHUFFLE_ADDRESSES:
     data->set.dns_shuffle_addresses = enabled;
@@ -1366,15 +1369,11 @@
     data->set.upkeep_interval_ms = arg;
     break;
   case CURLOPT_MAXAGE_CONN:
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.maxage_conn = arg;
-    break;
+    return setopt_set_timeout_sec(&data->set.conn_max_idle_ms, arg);
+
   case CURLOPT_MAXLIFETIME_CONN:
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.maxlifetime_conn = arg;
-    break;
+    return setopt_set_timeout_sec(&data->set.conn_max_age_ms, arg);
+
 #ifndef CURL_DISABLE_HSTS
   case CURLOPT_HSTS_CTRL:
     if(arg & CURLHSTS_ENABLE) {
@@ -1877,23 +1876,23 @@
     if(!ptr)
       break;
 
-    if(strcasecompare(ptr, "ALL")) {
+    if(curl_strequal(ptr, "ALL")) {
       /* clear all cookies */
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
       Curl_cookie_clearall(data->cookies);
       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
     }
-    else if(strcasecompare(ptr, "SESS")) {
+    else if(curl_strequal(ptr, "SESS")) {
       /* clear session cookies */
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
       Curl_cookie_clearsess(data->cookies);
       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
     }
-    else if(strcasecompare(ptr, "FLUSH")) {
+    else if(curl_strequal(ptr, "FLUSH")) {
       /* flush cookies to file, takes care of the locking */
       Curl_flush_cookies(data, FALSE);
     }
-    else if(strcasecompare(ptr, "RELOAD")) {
+    else if(curl_strequal(ptr, "RELOAD")) {
       /* reload cookies from file */
       Curl_cookie_loadfiles(data);
       break;
@@ -2557,12 +2556,12 @@
     return Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], ptr);
 #endif
   case CURLOPT_TLSAUTH_TYPE:
-    if(ptr && !strcasecompare(ptr, "SRP"))
+    if(ptr && !curl_strequal(ptr, "SRP"))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     break;
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_TLSAUTH_TYPE:
-    if(ptr && !strcasecompare(ptr, "SRP"))
+    if(ptr && !curl_strequal(ptr, "SRP"))
       return CURLE_BAD_FUNCTION_ARGUMENT;
     break;
 #endif
diff --git a/Utilities/cmcurl/lib/setup-vms.h b/Utilities/cmcurl/lib/setup-vms.h
index d74f4ad..0fd5e54 100644
--- a/Utilities/cmcurl/lib/setup-vms.h
+++ b/Utilities/cmcurl/lib/setup-vms.h
@@ -374,11 +374,9 @@
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #ifndef AI_NUMERICHOST
-#ifdef USE_IPV6
 #undef USE_IPV6
 #endif
 #endif
-#endif
 
 /* VAX symbols are always in uppercase */
 #ifdef __VAX
diff --git a/Utilities/cmcurl/lib/setup-win32.h b/Utilities/cmcurl/lib/setup-win32.h
index 35fe513..02177a7 100644
--- a/Utilities/cmcurl/lib/setup-win32.h
+++ b/Utilities/cmcurl/lib/setup-win32.h
@@ -30,10 +30,10 @@
 /* ---------------------------------------------------------------- */
 #ifdef USE_WATT32
 #  include <tcp.h>
+#  include <sys/socket.h>
 #  undef byte
 #  undef word
 #  define HAVE_SYS_IOCTL_H
-#  define HAVE_SYS_SOCKET_H
 #  define HAVE_NETINET_IN_H
 #  define HAVE_NETDB_H
 #  define HAVE_ARPA_INET_H
@@ -82,9 +82,6 @@
 #  include <windows.h>
 #  include <winerror.h>
 #  include <tchar.h>
-#  ifdef UNICODE
-     typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str);
-#  endif
 #endif
 
 /*
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
index ceca956..3eee164 100644
--- a/Utilities/cmcurl/lib/smb.c
+++ b/Utilities/cmcurl/lib/smb.c
@@ -543,7 +543,7 @@
                                  void **msg)
 {
   char *buf = smbc->recv_buf;
-  ssize_t bytes_read;
+  size_t bytes_read;
   size_t nbt_size;
   size_t msg_size;
   size_t len = MAX_MESSAGE_SIZE - smbc->got;
@@ -999,8 +999,8 @@
  */
 static void get_posix_time(time_t *out, curl_off_t timestamp)
 {
-  if(timestamp >= CURL_OFF_T_C(116444736000000000)) {
-    timestamp -= CURL_OFF_T_C(116444736000000000);
+  if(timestamp >= (curl_off_t)116444736000000000) {
+    timestamp -= (curl_off_t)116444736000000000;
     timestamp /= 10000000;
 #if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T
     if(timestamp > TIME_T_MAX)
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index d39bb58..d2adf43 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -68,7 +68,6 @@
 #include "mime.h"
 #include "socks.h"
 #include "smtp.h"
-#include "strcase.h"
 #include "vtls/vtls.h"
 #include "cfilters.h"
 #include "connect.h"
@@ -1625,13 +1624,12 @@
      bad in any way, sending quit and waiting around here will make the
      disconnect wait in vain and cause more problems than we need to. */
 
-  if(!dead_connection && conn->bits.protoconnstart) {
+  if(!dead_connection && conn->bits.protoconnstart &&
+     !Curl_pp_needs_flush(data, &smtpc->pp)) {
     if(!smtp_perform_quit(data, smtpc))
       (void)smtp_block_statemach(data, smtpc, TRUE); /* ignore on QUIT */
   }
 
-  /* Cleanup the SASL module */
-  Curl_sasl_cleanup(conn, smtpc->sasl.authused);
   CURL_TRC_SMTP(data, "smtp_disconnect(), finished");
   return CURLE_OK;
 }
@@ -1776,7 +1774,7 @@
     while(*ptr && *ptr != ';')
       ptr++;
 
-    if(strncasecompare(key, "AUTH=", 5))
+    if(curl_strnequal(key, "AUTH=", 5))
       result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
                                                value, ptr - value);
     else
@@ -2007,7 +2005,7 @@
           eob = &SMTP_EOB[2];
           break;
         case 3:
-          /* ended with '\r\n.', we should escpe the last '.' */
+          /* ended with '\r\n.', we should escape the last '.' */
           eob = "." SMTP_EOB;
           break;
         default:
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
index 08bc874..7d25ef5 100644
--- a/Utilities/cmcurl/lib/socks.c
+++ b/Utilities/cmcurl/lib/socks.c
@@ -81,7 +81,7 @@
 
 struct socks_state {
   enum connect_t state;
-  ssize_t outstanding;  /* send this many bytes more */
+  size_t outstanding;  /* send this many bytes more */
   unsigned char buffer[CURL_SOCKS_BUF_SIZE];
   unsigned char *outp; /* send from this pointer */
 
@@ -101,54 +101,41 @@
 int Curl_blockread_all(struct Curl_cfilter *cf,
                        struct Curl_easy *data,   /* transfer */
                        char *buf,                /* store read data here */
-                       ssize_t buffersize,       /* max amount to read */
-                       ssize_t *n)               /* amount bytes read */
+                       size_t blen,              /* space in buf */
+                       size_t *pnread)           /* amount bytes read */
 {
-  ssize_t nread = 0;
-  ssize_t allread = 0;
-  int result;
-  CURLcode err = CURLE_OK;
+  size_t nread = 0;
+  CURLcode err;
 
-  *n = 0;
+  *pnread = 0;
   for(;;) {
     timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
     if(timeout_ms < 0) {
       /* we already got the timeout */
-      result = CURLE_OPERATION_TIMEDOUT;
-      break;
+      return CURLE_OPERATION_TIMEDOUT;
     }
     if(!timeout_ms)
       timeout_ms = TIMEDIFF_T_MAX;
     if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) {
-      result = ~CURLE_OK;
-      break;
+      return ~CURLE_OK;
     }
-    nread = Curl_conn_cf_recv(cf->next, data, buf, buffersize, &err);
-    if(nread <= 0) {
-      result = (int)err;
-      if(CURLE_AGAIN == err)
-        continue;
-      if(err) {
-        break;
-      }
-    }
+    err = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread);
+    if(CURLE_AGAIN == err)
+      continue;
+    else if(err)
+      return (int)err;
 
-    if(buffersize == nread) {
-      allread += nread;
-      *n = allread;
-      result = CURLE_OK;
-      break;
+    if(blen == nread) {
+      *pnread += nread;
+      return CURLE_OK;
     }
-    if(!nread) {
-      result = ~CURLE_OK;
-      break;
-    }
+    if(!nread) /* EOF */
+      return ~CURLE_OK;
 
-    buffersize -= nread;
     buf += nread;
-    allread += nread;
+    blen -= nread;
+    *pnread += nread;
   }
-  return result;
 }
 #endif
 
@@ -213,24 +200,25 @@
                                       CURLproxycode failcode,
                                       const char *description)
 {
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
-  nwritten = Curl_conn_cf_send(cf->next, data, (char *)sx->outp,
-                               sx->outstanding, FALSE, &result);
-  if(nwritten <= 0) {
-    if(CURLE_AGAIN == result) {
+  result = Curl_conn_cf_send(cf->next, data, (char *)sx->outp,
+                             sx->outstanding, FALSE, &nwritten);
+  if(result) {
+    if(CURLE_AGAIN == result)
       return CURLPX_OK;
-    }
-    else if(CURLE_OK == result) {
-      /* connection closed */
-      failf(data, "connection to proxy closed");
-      return CURLPX_CLOSED;
-    }
+
     failf(data, "Failed to send %s: %s", description,
           curl_easy_strerror(result));
     return failcode;
   }
+  else if(!nwritten) {
+    /* connection closed */
+    failf(data, "connection to proxy closed");
+    return CURLPX_CLOSED;
+  }
+
   DEBUGASSERT(sx->outstanding >= nwritten);
   /* not done, remain in state */
   sx->outstanding -= nwritten;
@@ -244,24 +232,24 @@
                                       CURLproxycode failcode,
                                       const char *description)
 {
-  ssize_t nread;
+  size_t nread;
   CURLcode result;
 
-  nread = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp,
-                            sx->outstanding, &result);
-  if(nread <= 0) {
-    if(CURLE_AGAIN == result) {
+  result = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp,
+                            sx->outstanding, &nread);
+  if(result) {
+    if(CURLE_AGAIN == result)
       return CURLPX_OK;
-    }
-    else if(CURLE_OK == result) {
-      /* connection closed */
-      failf(data, "connection to proxy closed");
-      return CURLPX_CLOSED;
-    }
+
     failf(data, "SOCKS: Failed receiving %s: %s", description,
           curl_easy_strerror(result));
     return failcode;
   }
+  else if(!nread) {
+    /* connection closed */
+    failf(data, "connection to proxy closed");
+    return CURLPX_CLOSED;
+  }
   /* remain in reading state */
   DEBUGASSERT(sx->outstanding >= nread);
   sx->outstanding -= nread;
@@ -1158,8 +1146,8 @@
 }
 
 static void socks_cf_adjust_pollset(struct Curl_cfilter *cf,
-                                     struct Curl_easy *data,
-                                     struct easy_pollset *ps)
+                                    struct Curl_easy *data,
+                                    struct easy_pollset *ps)
 {
   struct socks_state *sx = cf->ctx;
 
@@ -1199,21 +1187,25 @@
   socks_proxy_cf_free(cf);
 }
 
-static void socks_cf_get_host(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              const char **phost,
-                              const char **pdisplay_host,
-                              int *pport)
+static CURLcode socks_cf_query(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               int query, int *pres1, void *pres2)
 {
-  (void)data;
-  if(!cf->connected) {
-    *phost = cf->conn->socks_proxy.host.name;
-    *pdisplay_host = cf->conn->http_proxy.host.dispname;
-    *pport = (int)cf->conn->socks_proxy.port;
+  struct socks_state *sx = cf->ctx;
+
+  if(sx) {
+    switch(query) {
+    case CF_QUERY_HOST_PORT:
+      *pres1 = sx->remote_port;
+      *((const char **)pres2) = sx->hostname;
+      return CURLE_OK;
+    default:
+      break;
+    }
   }
-  else {
-    cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
-  }
+  return cf->next ?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
 }
 
 struct Curl_cftype Curl_cft_socks_proxy = {
@@ -1224,7 +1216,6 @@
   socks_proxy_cf_connect,
   socks_proxy_cf_close,
   Curl_cf_def_shutdown,
-  socks_cf_get_host,
   socks_cf_adjust_pollset,
   Curl_cf_def_data_pending,
   Curl_cf_def_send,
@@ -1232,7 +1223,7 @@
   Curl_cf_def_cntrl,
   Curl_cf_def_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
-  Curl_cf_def_query,
+  socks_cf_query,
 };
 
 CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
diff --git a/Utilities/cmcurl/lib/socks.h b/Utilities/cmcurl/lib/socks.h
index a3adcc6..d607963 100644
--- a/Utilities/cmcurl/lib/socks.h
+++ b/Utilities/cmcurl/lib/socks.h
@@ -40,8 +40,8 @@
 int Curl_blockread_all(struct Curl_cfilter *cf,
                        struct Curl_easy *data,
                        char *buf,
-                       ssize_t buffersize,
-                       ssize_t *n);
+                       size_t blen,
+                       size_t *pnread);
 
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
 /*
diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c
index 697e301..f23a1ae 100644
--- a/Utilities/cmcurl/lib/socks_gssapi.c
+++ b/Utilities/cmcurl/lib/socks_gssapi.c
@@ -115,8 +115,8 @@
   struct connectdata *conn = cf->conn;
   curl_socket_t sock = conn->sock[cf->sockindex];
   CURLcode code;
-  ssize_t actualread;
-  ssize_t nwritten;
+  size_t actualread;
+  size_t nwritten;
   int result;
   OM_uint32 gss_major_status, gss_minor_status, gss_status;
   OM_uint32 gss_ret_flags;
@@ -199,7 +199,7 @@
       gss_release_name(&gss_status, &server);
       gss_release_buffer(&gss_status, &gss_recv_token);
       gss_release_buffer(&gss_status, &gss_send_token);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       failf(data, "Failed to initial GSS-API token.");
       return CURLE_COULDNT_CONNECT;
     }
@@ -210,26 +210,26 @@
       us_length = htons((unsigned short)gss_send_token.length);
       memcpy(socksreq + 2, &us_length, sizeof(short));
 
-      nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4,
-                                   FALSE, &code);
+      code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4,
+                               FALSE, &nwritten);
       if(code || (4 != nwritten)) {
         failf(data, "Failed to send GSS-API authentication request.");
         gss_release_name(&gss_status, &server);
         gss_release_buffer(&gss_status, &gss_recv_token);
         gss_release_buffer(&gss_status, &gss_send_token);
-        gss_delete_sec_context(&gss_status, &gss_context, NULL);
+        Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
         return CURLE_COULDNT_CONNECT;
       }
 
-      nwritten = Curl_conn_cf_send(cf->next, data,
-                                   (char *)gss_send_token.value,
-                                   gss_send_token.length, FALSE, &code);
-      if(code || ((ssize_t)gss_send_token.length != nwritten)) {
+      code = Curl_conn_cf_send(cf->next, data,
+                               (char *)gss_send_token.value,
+                               gss_send_token.length, FALSE, &nwritten);
+      if(code || (gss_send_token.length != nwritten)) {
         failf(data, "Failed to send GSS-API authentication token.");
         gss_release_name(&gss_status, &server);
         gss_release_buffer(&gss_status, &gss_recv_token);
         gss_release_buffer(&gss_status, &gss_send_token);
-        gss_delete_sec_context(&gss_status, &gss_context, NULL);
+        Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
         return CURLE_COULDNT_CONNECT;
       }
 
@@ -254,7 +254,7 @@
     if(result || (actualread != 4)) {
       failf(data, "Failed to receive GSS-API authentication response.");
       gss_release_name(&gss_status, &server);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_COULDNT_CONNECT;
     }
 
@@ -263,7 +263,7 @@
       failf(data, "User was rejected by the SOCKS5 server (%d %d).",
             socksreq[0], socksreq[1]);
       gss_release_name(&gss_status, &server);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_COULDNT_CONNECT;
     }
 
@@ -271,7 +271,7 @@
       failf(data, "Invalid GSS-API authentication response type (%d %d).",
             socksreq[0], socksreq[1]);
       gss_release_name(&gss_status, &server);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_COULDNT_CONNECT;
     }
 
@@ -285,7 +285,7 @@
             "Could not allocate memory for GSS-API authentication "
             "response token.");
       gss_release_name(&gss_status, &server);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_OUT_OF_MEMORY;
     }
 
@@ -296,7 +296,7 @@
       failf(data, "Failed to receive GSS-API authentication token.");
       gss_release_name(&gss_status, &server);
       gss_release_buffer(&gss_status, &gss_recv_token);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_COULDNT_CONNECT;
     }
 
@@ -311,7 +311,7 @@
                                          NULL, NULL, NULL);
   if(check_gss_err(data, gss_major_status,
                    gss_minor_status, "gss_inquire_context")) {
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     gss_release_name(&gss_status, &gss_client_name);
     failf(data, "Failed to determine username.");
     return CURLE_COULDNT_CONNECT;
@@ -320,7 +320,7 @@
                                       &gss_send_token, NULL);
   if(check_gss_err(data, gss_major_status,
                    gss_minor_status, "gss_display_name")) {
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     gss_release_name(&gss_status, &gss_client_name);
     gss_release_buffer(&gss_status, &gss_send_token);
     failf(data, "Failed to determine username.");
@@ -328,7 +328,7 @@
   }
   user = malloc(gss_send_token.length + 1);
   if(!user) {
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     gss_release_name(&gss_status, &gss_client_name);
     gss_release_buffer(&gss_status, &gss_send_token);
     return CURLE_OUT_OF_MEMORY;
@@ -397,7 +397,7 @@
     gss_send_token.length = 1;
     gss_send_token.value = Curl_memdup(&gss_enc, 1);
     if(!gss_send_token.value) {
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_OUT_OF_MEMORY;
     }
 
@@ -408,7 +408,7 @@
     if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) {
       gss_release_buffer(&gss_status, &gss_send_token);
       gss_release_buffer(&gss_status, &gss_w_token);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       failf(data, "Failed to wrap GSS-API encryption value into token.");
       return CURLE_COULDNT_CONNECT;
     }
@@ -418,33 +418,32 @@
     memcpy(socksreq + 2, &us_length, sizeof(short));
   }
 
-  nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
-                               &code);
-  if(code  || (4 != nwritten)) {
+  code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
+                           &nwritten);
+  if(code || (4 != nwritten)) {
     failf(data, "Failed to send GSS-API encryption request.");
     gss_release_buffer(&gss_status, &gss_w_token);
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     return CURLE_COULDNT_CONNECT;
   }
 
   if(data->set.socks5_gssapi_nec) {
     memcpy(socksreq, &gss_enc, 1);
-    nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
-                                 &code);
-    if(code || ( 1 != nwritten)) {
+    code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
+                             &nwritten);
+    if(code || (1 != nwritten)) {
       failf(data, "Failed to send GSS-API encryption type.");
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_COULDNT_CONNECT;
     }
   }
   else {
-    nwritten = Curl_conn_cf_send(cf->next, data,
-                                 (char *)gss_w_token.value,
-                                 gss_w_token.length, FALSE, &code);
-    if(code || ((ssize_t)gss_w_token.length != nwritten)) {
+    code = Curl_conn_cf_send(cf->next, data, (char *)gss_w_token.value,
+                             gss_w_token.length, FALSE, &nwritten);
+    if(code || (gss_w_token.length != nwritten)) {
       failf(data, "Failed to send GSS-API encryption type.");
       gss_release_buffer(&gss_status, &gss_w_token);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_COULDNT_CONNECT;
     }
     gss_release_buffer(&gss_status, &gss_w_token);
@@ -453,7 +452,7 @@
   result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
   if(result || (actualread != 4)) {
     failf(data, "Failed to receive GSS-API encryption response.");
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     return CURLE_COULDNT_CONNECT;
   }
 
@@ -461,14 +460,14 @@
   if(socksreq[1] == 255) { /* status / message type */
     failf(data, "User was rejected by the SOCKS5 server (%d %d).",
           socksreq[0], socksreq[1]);
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     return CURLE_COULDNT_CONNECT;
   }
 
   if(socksreq[1] != 2) { /* status / message type */
     failf(data, "Invalid GSS-API encryption response type (%d %d).",
           socksreq[0], socksreq[1]);
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     return CURLE_COULDNT_CONNECT;
   }
 
@@ -478,7 +477,7 @@
   gss_recv_token.length = us_length;
   gss_recv_token.value = malloc(gss_recv_token.length);
   if(!gss_recv_token.value) {
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     return CURLE_OUT_OF_MEMORY;
   }
   result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value,
@@ -487,7 +486,7 @@
   if(result || (actualread != us_length)) {
     failf(data, "Failed to receive GSS-API encryption type.");
     gss_release_buffer(&gss_status, &gss_recv_token);
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
     return CURLE_COULDNT_CONNECT;
   }
 
@@ -499,7 +498,7 @@
     if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) {
       gss_release_buffer(&gss_status, &gss_recv_token);
       gss_release_buffer(&gss_status, &gss_w_token);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       failf(data, "Failed to unwrap GSS-API encryption value into token.");
       return CURLE_COULDNT_CONNECT;
     }
@@ -509,7 +508,7 @@
       failf(data, "Invalid GSS-API encryption response length (%zu).",
             gss_w_token.length);
       gss_release_buffer(&gss_status, &gss_w_token);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_COULDNT_CONNECT;
     }
 
@@ -521,7 +520,7 @@
       failf(data, "Invalid GSS-API encryption response length (%zu).",
             gss_recv_token.length);
       gss_release_buffer(&gss_status, &gss_recv_token);
-      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
       return CURLE_COULDNT_CONNECT;
     }
 
@@ -538,7 +537,7 @@
 
   conn->socks5_gssapi_enctype = socksreq[0];
   if(socksreq[0] == 0)
-    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL);
 
   return CURLE_OK;
 }
diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c
index 1f0846d..8214756 100644
--- a/Utilities/cmcurl/lib/socks_sspi.c
+++ b/Utilities/cmcurl/lib/socks_sspi.c
@@ -69,8 +69,8 @@
   struct connectdata *conn = cf->conn;
   curl_socket_t sock = conn->sock[cf->sockindex];
   CURLcode code;
-  ssize_t actualread;
-  ssize_t written;
+  size_t actualread;
+  size_t written;
   int result;
   /* Needs GSS-API authentication */
   SECURITY_STATUS status;
@@ -207,8 +207,8 @@
       us_length = htons((unsigned short)sspi_send_token.cbBuffer);
       memcpy(socksreq + 2, &us_length, sizeof(short));
 
-      written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
-                                  &code);
+      code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
+                               &written);
       if(code || (4 != written)) {
         failf(data, "Failed to send SSPI authentication request.");
         free(service_name);
@@ -221,10 +221,10 @@
         return CURLE_COULDNT_CONNECT;
       }
 
-      written = Curl_conn_cf_send(cf->next, data,
-                                  (char *)sspi_send_token.pvBuffer,
-                                  sspi_send_token.cbBuffer, FALSE, &code);
-      if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
+      code = Curl_conn_cf_send(cf->next, data,
+                               (char *)sspi_send_token.pvBuffer,
+                               sspi_send_token.cbBuffer, FALSE, &written);
+      if(code || (sspi_send_token.cbBuffer != written)) {
         failf(data, "Failed to send SSPI authentication token.");
         free(service_name);
         if(sspi_send_token.pvBuffer)
@@ -478,8 +478,8 @@
     memcpy(socksreq + 2, &us_length, sizeof(short));
   }
 
-  written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
-                              &code);
+  code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
+                           &written);
   if(code || (4 != written)) {
     failf(data, "Failed to send SSPI encryption request.");
     if(sspi_send_token.pvBuffer)
@@ -490,8 +490,8 @@
 
   if(data->set.socks5_gssapi_nec) {
     memcpy(socksreq, &gss_enc, 1);
-    written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
-                                &code);
+    code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
+                             &written);
     if(code || (1 != written)) {
       failf(data, "Failed to send SSPI encryption type.");
       Curl_pSecFn->DeleteSecurityContext(&sspi_context);
@@ -499,9 +499,9 @@
     }
   }
   else {
-    written = Curl_conn_cf_send(cf->next, data,
-                                (char *)sspi_send_token.pvBuffer,
-                                sspi_send_token.cbBuffer, FALSE, &code);
+    code = Curl_conn_cf_send(cf->next, data,
+                             (char *)sspi_send_token.pvBuffer,
+                             sspi_send_token.cbBuffer, FALSE, &written);
     if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
       failf(data, "Failed to send SSPI encryption type.");
       if(sspi_send_token.pvBuffer)
diff --git a/Utilities/cmcurl/lib/speedcheck.c b/Utilities/cmcurl/lib/speedcheck.c
index 16d7d72..b063e5d 100644
--- a/Utilities/cmcurl/lib/speedcheck.c
+++ b/Utilities/cmcurl/lib/speedcheck.c
@@ -27,6 +27,7 @@
 #include <curl/curl.h>
 #include "urldata.h"
 #include "sendf.h"
+#include "transfer.h"
 #include "multiif.h"
 #include "speedcheck.h"
 
@@ -41,7 +42,7 @@
 CURLcode Curl_speedcheck(struct Curl_easy *data,
                          struct curltime now)
 {
-  if(data->req.keepon & KEEP_RECV_PAUSE)
+  if(Curl_xfer_recv_is_paused(data))
     /* A paused transfer is not qualified for speed checks */
     return CURLE_OK;
 
diff --git a/Utilities/cmcurl/lib/strcase.h b/Utilities/cmcurl/lib/strcase.h
index 8c50bbc..915c996 100644
--- a/Utilities/cmcurl/lib/strcase.h
+++ b/Utilities/cmcurl/lib/strcase.h
@@ -26,18 +26,6 @@
 
 #include <curl/curl.h>
 
-/*
- * Only "raw" case insensitive strings. This is meant to be locale independent
- * and only compare strings we know are safe for this.
- *
- * The function is capable of comparing a-z case insensitively.
- *
- * Result is 1 if text matches and 0 if not.
- */
-
-#define strcasecompare(a,b) curl_strequal(a,b)
-#define strncasecompare(a,b,c) curl_strnequal(a,b,c)
-
 char Curl_raw_toupper(char in);
 char Curl_raw_tolower(char in);
 
diff --git a/Utilities/cmcurl/lib/strequal.c b/Utilities/cmcurl/lib/strequal.c
index d1ba915..fb6be51 100644
--- a/Utilities/cmcurl/lib/strequal.c
+++ b/Utilities/cmcurl/lib/strequal.c
@@ -65,6 +65,15 @@
   return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
 }
 
+/*
+ * Only "raw" case insensitive strings. This is meant to be locale independent
+ * and only compare strings we know are safe for this.
+ *
+ * The function is capable of comparing a-z case insensitively.
+ *
+ * Result is 1 if text matches and 0 if not.
+ */
+
 /* --- public function --- */
 int curl_strequal(const char *first, const char *second)
 {
diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c
index 9cf93dd..9069488 100644
--- a/Utilities/cmcurl/lib/strerror.c
+++ b/Utilities/cmcurl/lib/strerror.c
@@ -317,36 +317,7 @@
     return "ECH attempted but failed";
 
     /* error codes not used by current libcurl */
-  case CURLE_OBSOLETE20:
-  case CURLE_OBSOLETE24:
-  case CURLE_OBSOLETE29:
-  case CURLE_OBSOLETE32:
-  case CURLE_OBSOLETE34:
-  case CURLE_OBSOLETE40:
-  case CURLE_OBSOLETE41:
-  case CURLE_OBSOLETE44:
-  case CURLE_OBSOLETE46:
-  case CURLE_OBSOLETE50:
-  case CURLE_OBSOLETE51:
-  case CURLE_OBSOLETE57:
-  case CURLE_OBSOLETE62:
-  case CURLE_OBSOLETE75:
-  case CURLE_OBSOLETE76:
-
-    /* error codes used by curl tests */
-  case CURLE_RESERVED115:
-  case CURLE_RESERVED116:
-  case CURLE_RESERVED117:
-  case CURLE_RESERVED118:
-  case CURLE_RESERVED119:
-  case CURLE_RESERVED120:
-  case CURLE_RESERVED121:
-  case CURLE_RESERVED122:
-  case CURLE_RESERVED123:
-  case CURLE_RESERVED124:
-  case CURLE_RESERVED125:
-  case CURLE_RESERVED126:
-  case CURL_LAST:
+  default:
     break;
   }
   /*
diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c
index 5212887..a890a0e 100644
--- a/Utilities/cmcurl/lib/system_win32.c
+++ b/Utilities/cmcurl/lib/system_win32.c
@@ -36,12 +36,17 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+#ifndef HAVE_IF_NAMETOINDEX
 /* Handle of iphlpapp.dll */
 static HMODULE s_hIpHlpApiDll = NULL;
 
 /* Pointer to the if_nametoindex function */
 IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL;
 
+/* This is used to dynamically load DLLs */
+static HMODULE curl_load_library(LPCTSTR filename);
+#endif
+
 /* Curl_win32_init() performs Win32 global initialization */
 CURLcode Curl_win32_init(long flags)
 {
@@ -90,7 +95,8 @@
   }
 #endif
 
-  s_hIpHlpApiDll = Curl_load_library(TEXT("iphlpapi.dll"));
+#ifndef HAVE_IF_NAMETOINDEX
+  s_hIpHlpApiDll = curl_load_library(TEXT("iphlpapi.dll"));
   if(s_hIpHlpApiDll) {
     /* Get the address of the if_nametoindex function */
 #ifdef UNDER_CE
@@ -106,6 +112,7 @@
     if(pIfNameToIndex)
       Curl_if_nametoindex = pIfNameToIndex;
   }
+#endif
 
   /* curlx_verify_windows_version must be called during init at least once
      because it has its own initialization routine. */
@@ -123,11 +130,13 @@
 /* Curl_win32_cleanup() is the opposite of Curl_win32_init() */
 void Curl_win32_cleanup(long init_flags)
 {
+#ifndef HAVE_IF_NAMETOINDEX
   if(s_hIpHlpApiDll) {
     FreeLibrary(s_hIpHlpApiDll);
     s_hIpHlpApiDll = NULL;
     Curl_if_nametoindex = NULL;
   }
+#endif
 
 #ifdef USE_WINDOWS_SSPI
   Curl_sspi_global_cleanup();
@@ -140,11 +149,13 @@
   }
 }
 
-#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
+#ifndef HAVE_IF_NAMETOINDEX
+
+#ifndef LOAD_WITH_ALTERED_SEARCH_PATH
 #define LOAD_WITH_ALTERED_SEARCH_PATH  0x00000008
 #endif
 
-#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
+#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
 #define LOAD_LIBRARY_SEARCH_SYSTEM32   0x00000800
 #endif
 
@@ -163,7 +174,7 @@
 #endif
 
 /*
- * Curl_load_library()
+ * curl_load_library()
  *
  * This is used to dynamically load DLLs using the most secure method available
  * for the version of Windows that we are running on.
@@ -176,7 +187,7 @@
  *
  * Returns the handle of the module on success; otherwise NULL.
  */
-HMODULE Curl_load_library(LPCTSTR filename)
+static HMODULE curl_load_library(LPCTSTR filename)
 {
 #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
   HMODULE hModule = NULL;
@@ -228,7 +239,6 @@
         hModule = pLoadLibraryEx ?
           pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
           LoadLibrary(path);
-
       }
       free(path);
     }
@@ -240,5 +250,6 @@
   return NULL;
 #endif
 }
+#endif /* !HAVE_IF_NAMETOINDEX */
 
 #endif /* _WIN32 */
diff --git a/Utilities/cmcurl/lib/system_win32.h b/Utilities/cmcurl/lib/system_win32.h
index b8333c6..6bf89d3 100644
--- a/Utilities/cmcurl/lib/system_win32.h
+++ b/Utilities/cmcurl/lib/system_win32.h
@@ -36,14 +36,13 @@
 CURLcode Curl_win32_init(long flags);
 void Curl_win32_cleanup(long init_flags);
 
+#ifndef HAVE_IF_NAMETOINDEX
 /* We use our own typedef here since some headers might lack this */
 typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *);
 
 /* This is used instead of if_nametoindex if available on Windows */
 extern IF_NAMETOINDEX_FN Curl_if_nametoindex;
-
-/* This is used to dynamically load DLLs */
-HMODULE Curl_load_library(LPCTSTR filename);
+#endif
 #else  /* _WIN32 */
 #define Curl_win32_init(x) CURLE_OK
 #endif /* !_WIN32 */
diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c
index 737db36..bd599de 100644
--- a/Utilities/cmcurl/lib/telnet.c
+++ b/Utilities/cmcurl/lib/telnet.c
@@ -57,7 +57,6 @@
 #include "system_win32.h"
 #include "arpa_telnet.h"
 #include "select.h"
-#include "strcase.h"
 #include "curlx/warnless.h"
 #include "curlx/strparse.h"
 
@@ -171,7 +170,7 @@
 
 static CURLcode telnet_do(struct Curl_easy *data, bool *done);
 static CURLcode telnet_done(struct Curl_easy *data,
-                                 CURLcode, bool premature);
+                            CURLcode, bool premature);
 static CURLcode send_telnet_data(struct Curl_easy *data,
                                  struct TELNET *tn,
                                  char *buffer, ssize_t nread);
@@ -839,7 +838,7 @@
       switch(olen) {
       case 5:
         /* Terminal type */
-        if(strncasecompare(option, "TTYPE", 5)) {
+        if(curl_strnequal(option, "TTYPE", 5)) {
           tn->subopt_ttype = arg;
           tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
           break;
@@ -849,7 +848,7 @@
 
       case 8:
         /* Display variable */
-        if(strncasecompare(option, "XDISPLOC", 8)) {
+        if(curl_strnequal(option, "XDISPLOC", 8)) {
           tn->subopt_xdisploc = arg;
           tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
           break;
@@ -859,7 +858,7 @@
 
       case 7:
         /* Environment variable */
-        if(strncasecompare(option, "NEW_ENV", 7)) {
+        if(curl_strnequal(option, "NEW_ENV", 7)) {
           beg = curl_slist_append(tn->telnet_vars, arg);
           if(!beg) {
             result = CURLE_OUT_OF_MEMORY;
@@ -874,7 +873,7 @@
 
       case 2:
         /* Window Size */
-        if(strncasecompare(option, "WS", 2)) {
+        if(curl_strnequal(option, "WS", 2)) {
           const char *p = arg;
           curl_off_t x = 0;
           curl_off_t y = 0;
@@ -896,7 +895,7 @@
 
       case 6:
         /* To take care or not of the 8th bit in data exchange */
-        if(strncasecompare(option, "BINARY", 6)) {
+        if(curl_strnequal(option, "BINARY", 6)) {
           int binary_option = atoi(arg);
           if(binary_option != 1) {
             tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
@@ -1314,8 +1313,8 @@
   int poll_cnt;
   curl_off_t total_dl = 0;
   curl_off_t total_ul = 0;
+  ssize_t snread;
 #endif
-  ssize_t nread;
   struct curltime now;
   bool keepon = TRUE;
   char buffer[4*1024];
@@ -1464,6 +1463,7 @@
       }
       if(events.lNetworkEvents & FD_READ) {
         /* read data from network */
+        size_t nread;
         result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
         /* read would have blocked. Loop again */
         if(result == CURLE_AGAIN)
@@ -1475,7 +1475,7 @@
         }
         /* returned zero but actually received 0 or less here,
            the server closed the connection and we bail out */
-        else if(nread <= 0) {
+        else if(!nread) {
           keepon = FALSE;
           break;
         }
@@ -1550,6 +1550,7 @@
     default:                    /* read! */
       if(pfd[0].revents & POLLIN) {
         /* read data from network */
+        size_t nread;
         result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
         /* read would have blocked. Loop again */
         if(result == CURLE_AGAIN)
@@ -1567,7 +1568,7 @@
         }
         /* returned zero but actually received 0 or less here,
            the server closed the connection and we bail out */
-        else if(nread <= 0) {
+        else if(!nread) {
           keepon = FALSE;
           break;
         }
@@ -1590,34 +1591,34 @@
         }
       }
 
-      nread = 0;
+      snread = 0;
       if(poll_cnt == 2) {
         if(pfd[1].revents & POLLIN) { /* read from in file */
-          nread = read(pfd[1].fd, buffer, sizeof(buffer));
+          snread = read(pfd[1].fd, buffer, sizeof(buffer));
         }
       }
       else {
         /* read from user-supplied method */
-        nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer),
+        snread = (int)data->state.fread_func(buffer, 1, sizeof(buffer),
                                             data->state.in);
-        if(nread == CURL_READFUNC_ABORT) {
+        if(snread == CURL_READFUNC_ABORT) {
           keepon = FALSE;
           break;
         }
-        if(nread == CURL_READFUNC_PAUSE)
+        if(snread == CURL_READFUNC_PAUSE)
           break;
       }
 
-      if(nread > 0) {
-        result = send_telnet_data(data, tn, buffer, nread);
+      if(snread > 0) {
+        result = send_telnet_data(data, tn, buffer, snread);
         if(result) {
           keepon = FALSE;
           break;
         }
-        total_ul += nread;
+        total_ul += snread;
         Curl_pgrsSetUploadCounter(data, total_ul);
       }
-      else if(nread < 0)
+      else if(snread < 0)
         keepon = FALSE;
 
       break;
diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c
index e9f4e68..5ea986d 100644
--- a/Utilities/cmcurl/lib/tftp.c
+++ b/Utilities/cmcurl/lib/tftp.c
@@ -48,6 +48,7 @@
 
 #include "urldata.h"
 #include <curl/curl.h>
+#include "cfilters.h"
 #include "cf-socket.h"
 #include "transfer.h"
 #include "sendf.h"
@@ -429,6 +430,7 @@
   const char *mode = "octet";
   char *filename;
   struct Curl_easy *data = state->data;
+  const struct Curl_sockaddr_ex *remote_addr = NULL;
   CURLcode result = CURLE_OK;
 
   /* Set ASCII mode if -B flag was used */
@@ -525,10 +527,14 @@
 #else
 #define CURL_SENDTO_ARG5(x) (x)
 #endif
+    remote_addr = Curl_conn_get_remote_addr(data, FIRSTSOCKET);
+    if(!remote_addr)
+      return CURLE_FAILED_INIT;
+
     senddata = sendto(state->sockfd, (void *)state->spacket.data,
                       (SEND_TYPE_ARG3)sbytes, 0,
-                      CURL_SENDTO_ARG5(&data->conn->remote_addr->curl_sa_addr),
-                      (curl_socklen_t)data->conn->remote_addr->addrlen);
+                      CURL_SENDTO_ARG5(&remote_addr->curl_sa_addr),
+                      (curl_socklen_t)remote_addr->addrlen);
     if(senddata != (ssize_t)sbytes) {
       char buffer[STRERROR_LEN];
       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
@@ -955,6 +961,7 @@
   int blksize;
   int need_blksize;
   struct connectdata *conn = data->conn;
+  const struct Curl_sockaddr_ex *remote_addr = NULL;
 
   blksize = TFTP_BLKSIZE_DEFAULT;
 
@@ -998,8 +1005,13 @@
   state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
   state->requested_blksize = blksize;
 
+  remote_addr = Curl_conn_get_remote_addr(data, FIRSTSOCKET);
+  DEBUGASSERT(remote_addr);
+  if(!remote_addr)
+    return CURLE_FAILED_INIT;
+
   ((struct sockaddr *)&state->local_addr)->sa_family =
-    (CURL_SA_FAMILY_T)(conn->remote_addr->family);
+    (CURL_SA_FAMILY_T)(remote_addr->family);
 
   tftp_set_timeouts(state);
 
@@ -1018,7 +1030,7 @@
      * IPv4 and IPv6...
      */
     int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
-                  (curl_socklen_t)conn->remote_addr->addrlen);
+                  (curl_socklen_t)remote_addr->addrlen);
     if(rc) {
       char buffer[STRERROR_LEN];
       failf(data, "bind() failed; %s",
@@ -1357,7 +1369,7 @@
 {
   char *type;
 
-  conn->transport = TRNSPRT_UDP;
+  conn->transport_wanted = TRNSPRT_UDP;
 
   /* TFTP URLs support an extension like ";mode=<typecode>" that
    * we will try to get now! */
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index ef7d7f1..15a61f6 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -79,7 +79,6 @@
 #include "connect.h"
 #include "http2.h"
 #include "mime.h"
-#include "strcase.h"
 #include "hsts.h"
 #include "setopt.h"
 #include "headers.h"
@@ -106,7 +105,7 @@
   DEBUGASSERT(thisheader[thislen-1] != ':');
 
   for(head = data->set.headers; head; head = head->next) {
-    if(strncasecompare(head->data, thisheader, thislen) &&
+    if(curl_strnequal(head->data, thisheader, thislen) &&
        Curl_headersep(head->data[thislen]) )
       return head->data;
   }
@@ -115,7 +114,7 @@
 }
 #endif
 
-static int data_pending(struct Curl_easy *data)
+static int data_pending(struct Curl_easy *data, bool rcvd_eagain)
 {
   struct connectdata *conn = data->conn;
 
@@ -124,8 +123,9 @@
 
   /* in the case of libssh2, we can never be really sure that we have emptied
      its internal buffers so we MUST always try until we get EAGAIN back */
-  return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
-    Curl_conn_data_pending(data, FIRSTSOCKET);
+  return (!rcvd_eagain &&
+          conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP)) ||
+         Curl_conn_data_pending(data, FIRSTSOCKET);
 }
 
 /*
@@ -210,7 +210,7 @@
                               bool eos_reliable,
                               CURLcode *err)
 {
-  ssize_t nread;
+  size_t nread;
 
   DEBUGASSERT(blen > 0);
   /* If we are reading BODY data and the connection does NOT handle EOF
@@ -251,8 +251,7 @@
     }
     DEBUGF(infof(data, "sendrecv_dl: we are done"));
   }
-  DEBUGASSERT(nread >= 0);
-  return nread;
+  return (ssize_t)nread;
 }
 
 /*
@@ -271,6 +270,7 @@
   int maxloops = 10;
   curl_off_t total_received = 0;
   bool is_multiplex = FALSE;
+  bool rcvd_eagain = FALSE;
 
   result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
   if(result)
@@ -303,23 +303,25 @@
         bytestoread = (size_t)data->set.max_recv_speed;
     }
 
+    rcvd_eagain = FALSE;
     nread = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &result);
     if(nread < 0) {
       if(CURLE_AGAIN != result)
         goto out; /* real error */
+      rcvd_eagain = TRUE;
       result = CURLE_OK;
       if(data->req.download_done && data->req.no_body &&
          !data->req.resp_trailer) {
         DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, "
                "not waiting for EOS"));
         nread = 0;
-        /* continue as if we read the EOS */
+        /* continue as if we received the EOS */
       }
       else
         break; /* get out of loop */
     }
 
-    /* We only get a 0-length read on EndOfStream */
+    /* We only get a 0-length receive at the end of the response */
     blen = (size_t)nread;
     is_eos = (blen == 0);
     *didwhat |= KEEP_RECV;
@@ -355,12 +357,12 @@
 
   } while(maxloops--);
 
-  if((maxloops <= 0) || data_pending(data)) {
-    /* did not read until EAGAIN or there is still pending data, mark as
-       read-again-please */
-    data->state.select_bits = CURL_CSELECT_IN;
-    if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
-      data->state.select_bits |= CURL_CSELECT_OUT;
+  if(!Curl_xfer_is_blocked(data) &&
+     (!rcvd_eagain || data_pending(data, rcvd_eagain))) {
+    /* Did not read until EAGAIN or there is still data pending
+     * in buffers. Mark as read-again via simulated SELECT results. */
+    Curl_multi_mark_dirty(data);
+    CURL_TRC_M(data, "sendrecv_dl() no EAGAIN/pending data, mark as dirty");
   }
 
   if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
@@ -396,24 +398,6 @@
   return CURLE_OK;
 }
 
-static int select_bits_paused(struct Curl_easy *data, int select_bits)
-{
-  /* See issue #11982: we really need to be careful not to progress
-   * a transfer direction when that direction is paused. Not all parts
-   * of our state machine are handling PAUSED transfers correctly. So, we
-   * do not want to go there.
-   * NOTE: we are only interested in PAUSE, not HOLD. */
-
-  /* if there is data in a direction not paused, return false */
-  if(((select_bits & CURL_CSELECT_IN) &&
-      !(data->req.keepon & KEEP_RECV_PAUSE)) ||
-     ((select_bits & CURL_CSELECT_OUT) &&
-      !(data->req.keepon & KEEP_SEND_PAUSE)))
-    return FALSE;
-
-  return (data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE));
-}
-
 /*
  * Curl_sendrecv() is the low-level function to be called when data is to
  * be read and written to/from the connection.
@@ -425,14 +409,9 @@
   int didwhat = 0;
 
   DEBUGASSERT(nowp);
-  if(data->state.select_bits) {
-    if(select_bits_paused(data, data->state.select_bits)) {
-      /* leave the bits unchanged, so they'll tell us what to do when
-       * this transfer gets unpaused. */
-      result = CURLE_OK;
-      goto out;
-    }
-    data->state.select_bits = 0;
+  if(Curl_xfer_is_blocked(data)) {
+    result = CURLE_OK;
+    goto out;
   }
 
   /* We go ahead and do a read if we have a readable socket or if the stream
@@ -948,7 +927,7 @@
 
 CURLcode Curl_xfer_recv(struct Curl_easy *data,
                         char *buf, size_t blen,
-                        ssize_t *pnrcvd)
+                        size_t *pnrcvd)
 {
   int sockindex;
 
@@ -974,9 +953,48 @@
   bool want_send = ((data)->req.keepon & KEEP_SEND);
   bool want_recv = ((data)->req.keepon & KEEP_RECV);
   if(!want_send)
-    return want_recv && Curl_cwriter_is_paused(data);
+    return want_recv && Curl_xfer_recv_is_paused(data);
   else if(!want_recv)
-    return want_send && Curl_creader_is_paused(data);
+    return want_send && Curl_xfer_send_is_paused(data);
   else
-    return Curl_creader_is_paused(data) && Curl_cwriter_is_paused(data);
+    return Curl_xfer_recv_is_paused(data) && Curl_xfer_send_is_paused(data);
+}
+
+bool Curl_xfer_send_is_paused(struct Curl_easy *data)
+{
+  return (data->req.keepon & KEEP_SEND_PAUSE);
+}
+
+bool Curl_xfer_recv_is_paused(struct Curl_easy *data)
+{
+  return (data->req.keepon & KEEP_RECV_PAUSE);
+}
+
+CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable)
+{
+  CURLcode result = CURLE_OK;
+  if(enable) {
+    data->req.keepon |= KEEP_SEND_PAUSE;
+  }
+  else {
+    data->req.keepon &= ~KEEP_SEND_PAUSE;
+    if(Curl_creader_is_paused(data))
+      result = Curl_creader_unpause(data);
+  }
+  return result;
+}
+
+CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable)
+{
+  CURLcode result = CURLE_OK;
+  if(enable) {
+    data->req.keepon |= KEEP_RECV_PAUSE;
+  }
+  else {
+    data->req.keepon &= ~KEEP_RECV_PAUSE;
+    if(Curl_cwriter_is_paused(data))
+      result = Curl_cwriter_unpause(data);
+  }
+  Curl_conn_ev_data_pause(data, enable);
+  return result;
 }
diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h
index 2c355e0..9227822 100644
--- a/Utilities/cmcurl/lib/transfer.h
+++ b/Utilities/cmcurl/lib/transfer.h
@@ -132,16 +132,23 @@
  */
 CURLcode Curl_xfer_recv(struct Curl_easy *data,
                         char *buf, size_t blen,
-                        ssize_t *pnrcvd);
+                        size_t *pnrcvd);
 
 CURLcode Curl_xfer_send_close(struct Curl_easy *data);
 CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done);
 
-/**
- * Return TRUE iff the transfer is not done, but further progress
+/* Return TRUE if the transfer is not done, but further progress
  * is blocked. For example when it is only receiving and its writer
- * is PAUSED.
- */
+ * is PAUSED. */
 bool Curl_xfer_is_blocked(struct Curl_easy *data);
 
+/* Query if send/recv for transfer is paused. */
+bool Curl_xfer_send_is_paused(struct Curl_easy *data);
+bool Curl_xfer_recv_is_paused(struct Curl_easy *data);
+
+/* Enable/Disable pausing of send/recv for the transfer. */
+CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable);
+CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable);
+
+
 #endif /* HEADER_CURL_TRANSFER_H */
diff --git a/Utilities/cmcurl/lib/uint-bset.c b/Utilities/cmcurl/lib/uint-bset.c
index 2560b37..e612c39 100644
--- a/Utilities/cmcurl/lib/uint-bset.c
+++ b/Utilities/cmcurl/lib/uint-bset.c
@@ -45,7 +45,8 @@
 
 CURLcode Curl_uint_bset_resize(struct uint_bset *bset, unsigned int nmax)
 {
-  unsigned int nslots = (nmax + 63) / 64;
+  unsigned int nslots = (nmax < (UINT_MAX-63)) ?
+                        ((nmax + 63) / 64) : (UINT_MAX / 64);
 
   DEBUGASSERT(bset->init == CURL_UINT_BSET_MAGIC);
   if(nslots != bset->nslots) {
@@ -60,6 +61,7 @@
     }
     bset->slots = slots;
     bset->nslots = nslots;
+    bset->first_slot_used = 0;
   }
   return CURLE_OK;
 }
@@ -72,14 +74,13 @@
   memset(bset, 0, sizeof(*bset));
 }
 
-
-unsigned int Curl_uint_bset_capacity(struct uint_bset *bset)
+#ifdef UNITTESTS
+UNITTEST unsigned int Curl_uint_bset_capacity(struct uint_bset *bset)
 {
   return bset->nslots * 64;
 }
 
-
-unsigned int Curl_uint_bset_count(struct uint_bset *bset)
+UNITTEST unsigned int Curl_uint_bset_count(struct uint_bset *bset)
 {
   unsigned int i;
   unsigned int n = 0;
@@ -89,12 +90,12 @@
   }
   return n;
 }
-
+#endif
 
 bool Curl_uint_bset_empty(struct uint_bset *bset)
 {
   unsigned int i;
-  for(i = 0; i < bset->nslots; ++i) {
+  for(i = bset->first_slot_used; i < bset->nslots; ++i) {
     if(bset->slots[i])
       return FALSE;
   }
@@ -104,8 +105,10 @@
 
 void Curl_uint_bset_clear(struct uint_bset *bset)
 {
-  if(bset->nslots)
+  if(bset->nslots) {
     memset(bset->slots, 0, bset->nslots * sizeof(curl_uint64_t));
+    bset->first_slot_used = UINT_MAX;
+  }
 }
 
 
@@ -115,6 +118,8 @@
   if(islot >= bset->nslots)
     return FALSE;
   bset->slots[islot] |= ((curl_uint64_t)1 << (i % 64));
+  if(islot < bset->first_slot_used)
+    bset->first_slot_used = islot;
   return TRUE;
 }
 
@@ -139,13 +144,14 @@
 bool Curl_uint_bset_first(struct uint_bset *bset, unsigned int *pfirst)
 {
   unsigned int i;
-  for(i = 0; i < bset->nslots; ++i) {
+  for(i = bset->first_slot_used; i < bset->nslots; ++i) {
     if(bset->slots[i]) {
       *pfirst = (i * 64) + CURL_CTZ64(bset->slots[i]);
+      bset->first_slot_used = i;
       return TRUE;
     }
   }
-  *pfirst = UINT_MAX; /* a value we cannot store */
+  bset->first_slot_used = *pfirst = UINT_MAX;
   return FALSE;
 }
 
@@ -183,11 +189,11 @@
   /* Compute the "Hamming Distance" between 'x' and 0,
    * which is the number of set bits in 'x'.
    * See: https://en.wikipedia.org/wiki/Hamming_weight */
-  const curl_uint64_t m1  = CURL_OFF_TU_C(0x5555555555555555); /* 0101+ */
-  const curl_uint64_t m2  = CURL_OFF_TU_C(0x3333333333333333); /* 00110011+ */
-  const curl_uint64_t m4  = CURL_OFF_TU_C(0x0f0f0f0f0f0f0f0f); /* 00001111+ */
+  const curl_uint64_t m1  = 0x5555555555555555LL; /* 0101+ */
+  const curl_uint64_t m2  = 0x3333333333333333LL; /* 00110011+ */
+  const curl_uint64_t m4  = 0x0f0f0f0f0f0f0f0fLL; /* 00001111+ */
    /* 1 + 256^1 + 256^2 + 256^3 + ... + 256^7 */
-  const curl_uint64_t h01 = CURL_OFF_TU_C(0x0101010101010101);
+  const curl_uint64_t h01 = 0x0101010101010101LL;
   x -= (x >> 1) & m1;             /* replace every 2 bits with bits present */
   x = (x & m2) + ((x >> 2) & m2); /* replace every nibble with bits present */
   x = (x + (x >> 4)) & m4;        /* replace every byte with bits present */
@@ -203,11 +209,11 @@
 {
   /* count trailing zeros in a curl_uint64_t.
    * divide and conquer to find the number of lower 0 bits */
-  const curl_uint64_t ml32 = CURL_OFF_TU_C(0xFFFFFFFF); /* lower 32 bits */
-  const curl_uint64_t ml16 = CURL_OFF_TU_C(0x0000FFFF); /* lower 16 bits */
-  const curl_uint64_t ml8  = CURL_OFF_TU_C(0x000000FF); /* lower 8 bits */
-  const curl_uint64_t ml4  = CURL_OFF_TU_C(0x0000000F); /* lower 4 bits */
-  const curl_uint64_t ml2  = CURL_OFF_TU_C(0x00000003); /* lower 2 bits */
+  const curl_uint64_t ml32 = 0xFFFFFFFF; /* lower 32 bits */
+  const curl_uint64_t ml16 = 0x0000FFFF; /* lower 16 bits */
+  const curl_uint64_t ml8  = 0x000000FF; /* lower 8 bits */
+  const curl_uint64_t ml4  = 0x0000000F; /* lower 4 bits */
+  const curl_uint64_t ml2  = 0x00000003; /* lower 2 bits */
   unsigned int n;
 
   if(!x)
diff --git a/Utilities/cmcurl/lib/uint-bset.h b/Utilities/cmcurl/lib/uint-bset.h
index d998dcc..cc405cc 100644
--- a/Utilities/cmcurl/lib/uint-bset.h
+++ b/Utilities/cmcurl/lib/uint-bset.h
@@ -42,6 +42,7 @@
 struct uint_bset {
   curl_uint64_t *slots;
   unsigned int nslots;
+  unsigned int first_slot_used;
 #ifdef DEBUGBUILD
   int init;
 #endif
diff --git a/Utilities/cmcurl/lib/uint-hash.c b/Utilities/cmcurl/lib/uint-hash.c
index afeb684..6c66507 100644
--- a/Utilities/cmcurl/lib/uint-hash.c
+++ b/Utilities/cmcurl/lib/uint-hash.c
@@ -107,8 +107,8 @@
 }
 
 static void uint_hash_elem_link(struct uint_hash *h,
-                                 struct uint_hash_entry **he_anchor,
-                                 struct uint_hash_entry *he)
+                                struct uint_hash_entry **he_anchor,
+                                struct uint_hash_entry *he)
 {
   he->next = *he_anchor;
   *he_anchor = he;
@@ -206,10 +206,12 @@
   }
 }
 
-void Curl_uint_hash_clear(struct uint_hash *h)
+#ifdef UNITTESTS
+UNITTEST void Curl_uint_hash_clear(struct uint_hash *h)
 {
   uint_hash_clear(h);
 }
+#endif
 
 void Curl_uint_hash_destroy(struct uint_hash *h)
 {
diff --git a/Utilities/cmcurl/lib/uint-spbset.c b/Utilities/cmcurl/lib/uint-spbset.c
index 578b9bd..d12cdcb 100644
--- a/Utilities/cmcurl/lib/uint-spbset.c
+++ b/Utilities/cmcurl/lib/uint-spbset.c
@@ -35,6 +35,9 @@
 #define CURL_UINT_SPBSET_MAGIC  0x70737362
 #endif
 
+/* Clear the bitset, making it empty. */
+UNITTEST void Curl_uint_spbset_clear(struct uint_spbset *bset);
+
 void Curl_uint_spbset_init(struct uint_spbset *bset)
 {
   memset(bset, 0, sizeof(*bset));
@@ -77,7 +80,7 @@
   return TRUE;
 }
 
-void Curl_uint_spbset_clear(struct uint_spbset *bset)
+UNITTEST void Curl_uint_spbset_clear(struct uint_spbset *bset)
 {
   struct uint_spbset_chunk *next, *chunk;
 
diff --git a/Utilities/cmcurl/lib/uint-spbset.h b/Utilities/cmcurl/lib/uint-spbset.h
index 571d567..bd23479 100644
--- a/Utilities/cmcurl/lib/uint-spbset.h
+++ b/Utilities/cmcurl/lib/uint-spbset.h
@@ -64,9 +64,6 @@
 /* TRUE of bitset is empty */
 bool Curl_uint_spbset_empty(struct uint_spbset *bset);
 
-/* Clear the bitset, making it empty. */
-void Curl_uint_spbset_clear(struct uint_spbset *bset);
-
 /* Add the number `i` to the bitset.
  * Numbers can be added more than once, without making a difference.
  * Returns FALSE if allocations failed. */
diff --git a/Utilities/cmcurl/lib/uint-table.c b/Utilities/cmcurl/lib/uint-table.c
index d8de1b1..21bcb6e 100644
--- a/Utilities/cmcurl/lib/uint-table.c
+++ b/Utilities/cmcurl/lib/uint-table.c
@@ -34,6 +34,9 @@
 #define CURL_UINT_TBL_MAGIC  0x62757473
 #endif
 
+/* Clear the table, making it empty. */
+UNITTEST void Curl_uint_tbl_clear(struct uint_tbl *tbl);
+
 void Curl_uint_tbl_init(struct uint_tbl *tbl,
                         Curl_uint_tbl_entry_dtor *entry_dtor)
 {
@@ -68,7 +71,7 @@
 {
   /* we use `tbl->nrows + 1` during iteration, want that to work */
   DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC);
-  if(!nrows || (nrows == UINT_MAX))
+  if(!nrows)
     return CURLE_BAD_FUNCTION_ARGUMENT;
   if(nrows != tbl->nrows) {
     void **rows = calloc(nrows, sizeof(void *));
@@ -95,8 +98,7 @@
   memset(tbl, 0, sizeof(*tbl));
 }
 
-
-void Curl_uint_tbl_clear(struct uint_tbl *tbl)
+UNITTEST void Curl_uint_tbl_clear(struct uint_tbl *tbl)
 {
   DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC);
   uint_tbl_clear_rows(tbl, 0, tbl->nrows);
@@ -130,7 +132,7 @@
   DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC);
   if(!entry || !pkey)
     return FALSE;
-  *pkey = UINT_MAX; /* always invalid */
+  *pkey = UINT_MAX;
   if(tbl->nentries == tbl->nrows)  /* full */
     return FALSE;
 
diff --git a/Utilities/cmcurl/lib/uint-table.h b/Utilities/cmcurl/lib/uint-table.h
index 2c05b1d..c74ec7a 100644
--- a/Utilities/cmcurl/lib/uint-table.h
+++ b/Utilities/cmcurl/lib/uint-table.h
@@ -60,9 +60,6 @@
 /* Get the number of entries in the table. */
 unsigned int Curl_uint_tbl_count(struct uint_tbl *tbl);
 
-/* Clear the table, making it empty. */
-void Curl_uint_tbl_clear(struct uint_tbl *tbl);
-
 /* Get the entry for key or NULL if not present */
 void *Curl_uint_tbl_get(struct uint_tbl *tbl, unsigned int key);
 
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index 10e37ec..e4f250f 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -59,6 +59,10 @@
 #error "We cannot compile without socket() support!"
 #endif
 
+#if defined(HAVE_IF_NAMETOINDEX) && defined(_WIN32)
+#include <iphlpapi.h>
+#endif
+
 #include <limits.h>
 
 #include "doh.h"
@@ -107,7 +111,6 @@
 #include "imap.h"
 #include "url.h"
 #include "connect.h"
-#include "inet_ntop.h"
 #include "http_ntlm.h"
 #include "curl_rtmp.h"
 #include "gopher.h"
@@ -231,22 +234,24 @@
   data = *datap;
   *datap = NULL;
 
-  /* Detach connection if any is left. This should not be normal, but can be
-     the case for example with CONNECT_ONLY + recv/send (test 556) */
-  Curl_detach_connection(data);
-  if(!data->state.internal) {
-    if(data->multi)
-      /* This handle is still part of a multi handle, take care of this first
-         and detach this handle from there. */
-      curl_multi_remove_handle(data->multi, data);
-
-    if(data->multi_easy) {
+  if(!data->state.internal && data->multi) {
+    /* This handle is still part of a multi handle, take care of this first
+       and detach this handle from there.
+       This detaches the connection. */
+    curl_multi_remove_handle(data->multi, data);
+  }
+  else {
+    /* Detach connection if any is left. This should not be normal, but can be
+       the case for example with CONNECT_ONLY + recv/send (test 556) */
+    Curl_detach_connection(data);
+    if(!data->state.internal && data->multi_easy) {
       /* when curl_easy_perform() is used, it creates its own multi handle to
          use and this is the one */
       curl_multi_cleanup(data->multi_easy);
       data->multi_easy = NULL;
     }
   }
+  DEBUGASSERT(!data->conn || data->state.internal);
 
   Curl_expire_clear(data); /* shut off any timers left */
 
@@ -422,13 +427,11 @@
 
   /* Set the default CA cert bundle/path detected/specified at build time.
    *
-   * If Schannel or Secure Transport is the selected SSL backend then these
-   * locations are ignored. We allow setting CA location for Schannel and
-   * Secure Transport when explicitly specified by the user via
-   *  CURLOPT_CAINFO / --cacert.
+   * If Schannel is the selected SSL backend then these locations are ignored.
+   * We allow setting CA location for Schannel when explicitly specified by
+   * the user via CURLOPT_CAINFO / --cacert.
    */
-  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL &&
-     Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) {
+  if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
 #ifdef CURL_CA_BUNDLE
     result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
     if(result)
@@ -472,8 +475,8 @@
   set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
   set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
   set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
-  set->maxage_conn = 118;
-  set->maxlifetime_conn = 0;
+  set->conn_max_idle_ms = 118 * 1000;
+  set->conn_max_age_ms = 0;
   set->http09_allowed = FALSE;
   set->httpwant = CURL_HTTP_VERSION_NONE
     ;
@@ -640,7 +643,7 @@
 {
   if((data->proxytype == needle->proxytype) &&
      (data->port == needle->port) &&
-     strcasecompare(data->host.name, needle->host.name))
+     curl_strequal(data->host.name, needle->host.name))
     return TRUE;
 
   return FALSE;
@@ -670,36 +673,36 @@
 #define socks_proxy_info_matches(x,y) FALSE
 #endif
 
-/* A connection has to have been idle for a shorter time than 'maxage_conn'
+/* A connection has to have been idle for less than 'conn_max_idle_ms'
    (the success rate is just too low after this), or created less than
-   'maxlifetime_conn' ago, to be subject for reuse. */
-
+   'conn_max_age_ms' ago, to be subject for reuse. */
 static bool conn_maxage(struct Curl_easy *data,
                         struct connectdata *conn,
                         struct curltime now)
 {
-  timediff_t idletime, lifetime;
+  timediff_t age_ms;
 
-  idletime = curlx_timediff(now, conn->lastused);
-  idletime /= 1000; /* integer seconds is fine */
-
-  if(idletime > data->set.maxage_conn) {
-    infof(data, "Too old connection (%" FMT_TIMEDIFF_T
-          " seconds idle), disconnect it", idletime);
-    return TRUE;
+  if(data->set.conn_max_idle_ms) {
+    age_ms = curlx_timediff(now, conn->lastused);
+    if(age_ms > data->set.conn_max_idle_ms) {
+      infof(data, "Too old connection (%" FMT_TIMEDIFF_T
+            " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it",
+            age_ms, data->set.conn_max_idle_ms);
+      return TRUE;
+    }
   }
 
-  lifetime = curlx_timediff(now, conn->created);
-  lifetime /= 1000; /* integer seconds is fine */
-
-  if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) {
-    infof(data,
-          "Too old connection (%" FMT_TIMEDIFF_T
-          " seconds since creation), disconnect it", lifetime);
-    return TRUE;
+  if(data->set.conn_max_age_ms) {
+    age_ms = curlx_timediff(now, conn->created);
+    if(age_ms > data->set.conn_max_age_ms) {
+      infof(data,
+            "Too old connection (created %" FMT_TIMEDIFF_T
+            " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it",
+            age_ms, data->set.conn_max_age_ms);
+      return TRUE;
+    }
   }
 
-
   return FALSE;
 }
 
@@ -1125,7 +1128,7 @@
      || !m->needle->bits.httpproxy || m->needle->bits.tunnel_proxy
 #endif
     ) {
-    if(!strcasecompare(m->needle->handler->scheme, conn->handler->scheme)) {
+    if(!curl_strequal(m->needle->handler->scheme, conn->handler->scheme)) {
       /* `needle` and `conn` do not have the same scheme... */
       if(get_protocol_family(conn->handler) != m->needle->handler->protocol) {
         /* and `conn`s protocol family is not the protocol `needle` wants.
@@ -1142,14 +1145,14 @@
     }
 
     /* If needle has "conn_to_*" set, conn must match this */
-    if((m->needle->bits.conn_to_host && !strcasecompare(
+    if((m->needle->bits.conn_to_host && !curl_strequal(
         m->needle->conn_to_host.name, conn->conn_to_host.name)) ||
        (m->needle->bits.conn_to_port &&
          m->needle->conn_to_port != conn->conn_to_port))
       return FALSE;
 
     /* hostname and port must match */
-    if(!strcasecompare(m->needle->host.name, conn->host.name) ||
+    if(!curl_strequal(m->needle->host.name, conn->host.name) ||
        m->needle->remote_port != conn->remote_port)
       return FALSE;
   }
@@ -1461,7 +1464,7 @@
 #endif
   conn->ip_version = data->set.ipver;
   conn->connect_only = data->set.connect_only;
-  conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
+  conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
 
   /* Initialize the attached xfers bitset */
   Curl_uint_spbset_init(&conn->xfers_attached);
@@ -1711,7 +1714,7 @@
     }
 
     h = protocols[c % 67];
-    if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len])
+    if(h && curl_strnequal(scheme, h->scheme, len) && !h->scheme[len])
       return h;
   }
   return NULL;
@@ -1795,10 +1798,10 @@
 #if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
       /* Zone identifier is not numeric */
       unsigned int scopeidx = 0;
-#ifdef _WIN32
-      scopeidx = Curl_if_nametoindex(zoneid);
-#else
+#ifdef HAVE_IF_NAMETOINDEX
       scopeidx = if_nametoindex(zoneid);
+#else
+      scopeidx = Curl_if_nametoindex(zoneid);
 #endif
       if(!scopeidx) {
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -1885,7 +1888,7 @@
 
   uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
   if(uc) {
-    if(!strcasecompare("file", data->state.up.scheme))
+    if(!curl_strequal("file", data->state.up.scheme))
       return CURLE_OUT_OF_MEMORY;
   }
   else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
@@ -1922,7 +1925,7 @@
 
 #ifndef CURL_DISABLE_HSTS
   /* HSTS upgrade */
-  if(data->hsts && strcasecompare("http", data->state.up.scheme)) {
+  if(data->hsts && curl_strequal("http", data->state.up.scheme)) {
     /* This MUST use the IDN decoded name */
     if(Curl_hsts(data->hsts, conn->host.name, strlen(conn->host.name), TRUE)) {
       char *url;
@@ -2016,7 +2019,7 @@
   uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
                     CURLU_DEFAULT_PORT);
   if(uc) {
-    if(!strcasecompare("file", data->state.up.scheme))
+    if(!curl_strequal("file", data->state.up.scheme))
       return CURLE_OUT_OF_MEMORY;
   }
   else {
@@ -2195,7 +2198,7 @@
    * This can cause 'internal' http/ftp requests to be
    * arbitrarily redirected by any external attacker.
    */
-  if(!proxy && !strcasecompare("http_proxy", proxy_env)) {
+  if(!proxy && !curl_strequal("http_proxy", proxy_env)) {
     /* There was no lowercase variable, try the uppercase version: */
     Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
     proxy = curl_getenv(proxy_env);
@@ -2204,10 +2207,10 @@
   if(!proxy) {
 #ifndef CURL_DISABLE_WEBSOCKETS
     /* websocket proxy fallbacks */
-    if(strcasecompare("ws_proxy", proxy_env)) {
+    if(curl_strequal("ws_proxy", proxy_env)) {
       proxy = curl_getenv("http_proxy");
     }
-    else if(strcasecompare("wss_proxy", proxy_env)) {
+    else if(curl_strequal("wss_proxy", proxy_env)) {
       proxy = curl_getenv("https_proxy");
       if(!proxy)
         proxy = curl_getenv("HTTPS_PROXY");
@@ -2274,22 +2277,22 @@
       goto error;
     }
 
-    if(strcasecompare("https", scheme)) {
+    if(curl_strequal("https", scheme)) {
       if(proxytype != CURLPROXY_HTTPS2)
         proxytype = CURLPROXY_HTTPS;
       else
         proxytype = CURLPROXY_HTTPS2;
     }
-    else if(strcasecompare("socks5h", scheme))
+    else if(curl_strequal("socks5h", scheme))
       proxytype = CURLPROXY_SOCKS5_HOSTNAME;
-    else if(strcasecompare("socks5", scheme))
+    else if(curl_strequal("socks5", scheme))
       proxytype = CURLPROXY_SOCKS5;
-    else if(strcasecompare("socks4a", scheme))
+    else if(curl_strequal("socks4a", scheme))
       proxytype = CURLPROXY_SOCKS4A;
-    else if(strcasecompare("socks4", scheme) ||
-            strcasecompare("socks", scheme))
+    else if(curl_strequal("socks4", scheme) ||
+            curl_strequal("socks", scheme))
       proxytype = CURLPROXY_SOCKS4;
-    else if(strcasecompare("http", scheme))
+    else if(curl_strequal("http", scheme))
       ; /* leave it as HTTP or HTTP/1.0 */
     else {
       /* Any other xxx:// reject! */
@@ -2390,7 +2393,7 @@
     goto error;
   }
 #ifdef USE_UNIX_SOCKETS
-  if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
+  if(sockstype && curl_strequal(UNIX_SOCKET_PREFIX, host)) {
     uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE);
     if(uc) {
       result = CURLE_OUT_OF_MEMORY;
@@ -2757,16 +2760,20 @@
   return CURLE_OK;
 }
 
+#ifndef CURL_DISABLE_NETRC
 static bool str_has_ctrl(const char *input)
 {
-  const unsigned char *str = (const unsigned char *)input;
-  while(*str) {
-    if(*str < 0x20)
-      return TRUE;
-    str++;
+  if(input) {
+    const unsigned char *str = (const unsigned char *)input;
+    while(*str) {
+      if(*str < 0x20)
+        return TRUE;
+      str++;
+    }
   }
   return FALSE;
 }
+#endif
 
 /*
  * Override the login details from the URL with that in the CURLOPT_USERPWD
@@ -3062,8 +3069,8 @@
     if(!hostname_to_match)
       return CURLE_OUT_OF_MEMORY;
     hostname_to_match_len = strlen(hostname_to_match);
-    host_match = strncasecompare(ptr, hostname_to_match,
-                                 hostname_to_match_len);
+    host_match = curl_strnequal(ptr, hostname_to_match,
+                                hostname_to_match_len);
     free(hostname_to_match);
     ptr += hostname_to_match_len;
 
@@ -3228,7 +3235,7 @@
           neg->wanted = neg->allowed = CURL_HTTP_V2x;
           break;
         case ALPN_h3:
-          conn->transport = TRNSPRT_QUIC;
+          conn->transport_wanted = TRNSPRT_QUIC;
           neg->wanted = neg->allowed = CURL_HTTP_V3x;
           break;
         default: /* should not be possible */
@@ -3305,7 +3312,7 @@
 
     if(unix_path) {
       /* This only works if previous transport is TRNSPRT_TCP. Check it? */
-      conn->transport = TRNSPRT_UNIX;
+      conn->transport_wanted = TRNSPRT_UNIX;
       return resolve_unix(data, conn, unix_path, pdns);
     }
   }
@@ -3596,7 +3603,7 @@
    * Do this after the hostnames have been IDN-converted.
    *************************************************************/
   if(conn->bits.conn_to_host &&
-     strcasecompare(conn->conn_to_host.name, conn->host.name)) {
+     curl_strequal(conn->conn_to_host.name, conn->host.name)) {
     conn->bits.conn_to_host = FALSE;
   }
 
@@ -4094,3 +4101,17 @@
 {
   return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
 }
+
+CURLcode Curl_1st_err(CURLcode r1, CURLcode r2)
+{
+  return r1 ? r1 : r2;
+}
+
+CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2)
+{
+  if(r1 && (r1 != CURLE_AGAIN))
+    return r1;
+  if(r2 && (r2 != CURLE_AGAIN))
+    return r2;
+  return r1;
+}
diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h
index 7aba98d..bd4060c 100644
--- a/Utilities/cmcurl/lib/url.h
+++ b/Utilities/cmcurl/lib/url.h
@@ -101,6 +101,19 @@
                           struct connectdata *conn,
                           struct curltime *now);
 
+/**
+ * Always eval all arguments, return the first result != CURLE_OK.
+ * A non-short-circuit evaluation.
+ */
+CURLcode Curl_1st_err(CURLcode r1, CURLcode r2);
+
+/**
+ * Always eval all arguments, return the first
+ * result != (CURLE_OK|CURLE_AGAIN) or `r1`.
+ * A non-short-circuit evaluation.
+ */
+CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2);
+
 #if defined(USE_HTTP2) || defined(USE_HTTP3)
 void Curl_data_priority_clear_state(struct Curl_easy *data);
 #else
diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index 6a7ab1a..c266fd3 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/urlapi.c
@@ -31,7 +31,7 @@
 #include "escape.h"
 #include "curl_ctype.h"
 #include "curlx/inet_pton.h"
-#include "inet_ntop.h"
+#include "curlx/inet_ntop.h"
 #include "strdup.h"
 #include "idn.h"
 #include "curlx/strparse.h"
@@ -164,7 +164,7 @@
     }
     else if((*iptr < ' ') || (*iptr >= 0x7f)) {
       unsigned char out[3]={'%'};
-      Curl_hexbyte(&out[1], *iptr, TRUE);
+      Curl_hexbyte(&out[1], *iptr);
       result = curlx_dyn_addn(o, out, 3);
     }
     else {
@@ -513,7 +513,7 @@
     hostname[hlen] = 0; /* end the address there */
     if(1 != curlx_inet_pton(AF_INET6, hostname, dest))
       return CURLUE_BAD_IPV6;
-    if(Curl_inet_ntop(AF_INET6, dest, hostname, hlen)) {
+    if(curlx_inet_ntop(AF_INET6, dest, hostname, hlen)) {
       hlen = strlen(hostname); /* might be shorter now */
       hostname[hlen + 1] = 0;
     }
@@ -1320,18 +1320,221 @@
   return NULL;
 }
 
+#ifndef USE_IDN
+#define host_decode(x,y) CURLUE_LACKS_IDN
+#define host_encode(x,y) CURLUE_LACKS_IDN
+#else
+static CURLUcode host_decode(const char *host, char **allochost)
+{
+  CURLcode result = Curl_idn_decode(host, allochost);
+  if(result)
+    return (result == CURLE_OUT_OF_MEMORY) ?
+      CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
+  return CURLUE_OK;
+}
+
+static CURLUcode host_encode(const char *host, char **allochost)
+{
+  CURLcode result = Curl_idn_encode(host, allochost);
+  if(result)
+    return (result == CURLE_OUT_OF_MEMORY) ?
+      CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
+  return CURLUE_OK;
+}
+#endif
+
+static CURLUcode urlget_format(const CURLU *u, CURLUPart what,
+                               const char *ptr, char **part,
+                               bool plusdecode, unsigned int flags)
+{
+  size_t partlen = strlen(ptr);
+  bool urldecode = (flags & CURLU_URLDECODE) ? 1 : 0;
+  bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0;
+  bool punycode = (flags & CURLU_PUNYCODE) && (what == CURLUPART_HOST);
+  bool depunyfy = (flags & CURLU_PUNY2IDN) && (what == CURLUPART_HOST);
+  *part = Curl_memdup0(ptr, partlen);
+  if(!*part)
+    return CURLUE_OUT_OF_MEMORY;
+  if(plusdecode) {
+    /* convert + to space */
+    char *plus = *part;
+    size_t i = 0;
+    for(i = 0; i < partlen; ++plus, i++) {
+      if(*plus == '+')
+        *plus = ' ';
+    }
+  }
+  if(urldecode) {
+    char *decoded;
+    size_t dlen;
+    /* this unconditional rejection of control bytes is documented
+       API behavior */
+    CURLcode res = Curl_urldecode(*part, 0, &decoded, &dlen, REJECT_CTRL);
+    free(*part);
+    if(res) {
+      *part = NULL;
+      return CURLUE_URLDECODE;
+    }
+    *part = decoded;
+    partlen = dlen;
+  }
+  if(urlencode) {
+    struct dynbuf enc;
+    CURLUcode uc;
+    curlx_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
+    uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY);
+    if(uc)
+      return uc;
+    free(*part);
+    *part = curlx_dyn_ptr(&enc);
+  }
+  else if(punycode) {
+    if(!Curl_is_ASCII_name(u->host)) {
+      char *allochost = NULL;
+      CURLUcode ret = host_decode(*part, &allochost);
+      if(ret)
+        return ret;
+      free(*part);
+      *part = allochost;
+    }
+  }
+  else if(depunyfy) {
+    if(Curl_is_ASCII_name(u->host)) {
+      char *allochost = NULL;
+      CURLUcode ret = host_encode(*part, &allochost);
+      if(ret)
+        return ret;
+      free(*part);
+      *part = allochost;
+    }
+  }
+
+  return CURLUE_OK;
+}
+
+static CURLUcode urlget_url(const CURLU *u, char **part, unsigned int flags)
+{
+  char *url;
+  const char *scheme;
+  char *options = u->options;
+  char *port = u->port;
+  char *allochost = NULL;
+  bool show_fragment =
+    u->fragment || (u->fragment_present && flags & CURLU_GET_EMPTY);
+  bool show_query = (u->query && u->query[0]) ||
+    (u->query_present && flags & CURLU_GET_EMPTY);
+  bool punycode = (flags & CURLU_PUNYCODE) ? 1 : 0;
+  bool depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0;
+  bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0;
+  char portbuf[7];
+  if(u->scheme && curl_strequal("file", u->scheme)) {
+    url = aprintf("file://%s%s%s%s%s",
+                  u->path,
+                  show_query ? "?": "",
+                  u->query ? u->query : "",
+                  show_fragment ? "#": "",
+                  u->fragment ? u->fragment : "");
+  }
+  else if(!u->host)
+    return CURLUE_NO_HOST;
+  else {
+    const struct Curl_handler *h = NULL;
+    char schemebuf[MAX_SCHEME_LEN + 5];
+    if(u->scheme)
+      scheme = u->scheme;
+    else if(flags & CURLU_DEFAULT_SCHEME)
+      scheme = DEFAULT_SCHEME;
+    else
+      return CURLUE_NO_SCHEME;
+
+    h = Curl_get_scheme_handler(scheme);
+    if(!port && (flags & CURLU_DEFAULT_PORT)) {
+      /* there is no stored port number, but asked to deliver
+         a default one for the scheme */
+      if(h) {
+        msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
+        port = portbuf;
+      }
+    }
+    else if(port) {
+      /* there is a stored port number, but asked to inhibit if it matches
+         the default one for the scheme */
+      if(h && (h->defport == u->portnum) &&
+         (flags & CURLU_NO_DEFAULT_PORT))
+        port = NULL;
+    }
+
+    if(h && !(h->flags & PROTOPT_URLOPTIONS))
+      options = NULL;
+
+    if(u->host[0] == '[') {
+      if(u->zoneid) {
+        /* make it '[ host %25 zoneid ]' */
+        struct dynbuf enc;
+        size_t hostlen = strlen(u->host);
+        curlx_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
+        if(curlx_dyn_addf(&enc, "%.*s%%25%s]", (int)hostlen - 1, u->host,
+                          u->zoneid))
+          return CURLUE_OUT_OF_MEMORY;
+        allochost = curlx_dyn_ptr(&enc);
+      }
+    }
+    else if(urlencode) {
+      allochost = curl_easy_escape(NULL, u->host, 0);
+      if(!allochost)
+        return CURLUE_OUT_OF_MEMORY;
+    }
+    else if(punycode) {
+      if(!Curl_is_ASCII_name(u->host)) {
+        CURLUcode ret = host_decode(u->host, &allochost);
+        if(ret)
+          return ret;
+      }
+    }
+    else if(depunyfy) {
+      if(Curl_is_ASCII_name(u->host)) {
+        CURLUcode ret = host_encode(u->host, &allochost);
+        if(ret)
+          return ret;
+      }
+    }
+
+    if(!(flags & CURLU_NO_GUESS_SCHEME) || !u->guessed_scheme)
+      msnprintf(schemebuf, sizeof(schemebuf), "%s://", scheme);
+    else
+      schemebuf[0] = 0;
+
+    url = aprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+                  schemebuf,
+                  u->user ? u->user : "",
+                  u->password ? ":": "",
+                  u->password ? u->password : "",
+                  options ? ";" : "",
+                  options ? options : "",
+                  (u->user || u->password || options) ? "@": "",
+                  allochost ? allochost : u->host,
+                  port ? ":": "",
+                  port ? port : "",
+                  u->path ? u->path : "/",
+                  show_query ? "?": "",
+                  u->query ? u->query : "",
+                  show_fragment ? "#": "",
+                  u->fragment ? u->fragment : "");
+    free(allochost);
+  }
+  if(!url)
+    return CURLUE_OUT_OF_MEMORY;
+  *part = url;
+  return CURLUE_OK;
+}
+
 CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
                        char **part, unsigned int flags)
 {
   const char *ptr;
   CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
   char portbuf[7];
-  bool urldecode = (flags & CURLU_URLDECODE) ? 1 : 0;
-  bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0;
-  bool punycode = FALSE;
-  bool depunyfy = FALSE;
   bool plusdecode = FALSE;
-  (void)flags;
   if(!u)
     return CURLUE_BAD_HANDLE;
   if(!part)
@@ -1342,7 +1545,7 @@
   case CURLUPART_SCHEME:
     ptr = u->scheme;
     ifmissing = CURLUE_NO_SCHEME;
-    urldecode = FALSE; /* never for schemes */
+    flags &= ~CURLU_URLDECODE; /* never for schemes */
     if((flags & CURLU_NO_GUESS_SCHEME) && u->guessed_scheme)
       return CURLUE_NO_SCHEME;
     break;
@@ -1361,8 +1564,6 @@
   case CURLUPART_HOST:
     ptr = u->host;
     ifmissing = CURLUE_NO_HOST;
-    punycode = (flags & CURLU_PUNYCODE) ? 1 : 0;
-    depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0;
     break;
   case CURLUPART_ZONEID:
     ptr = u->zoneid;
@@ -1371,7 +1572,7 @@
   case CURLUPART_PORT:
     ptr = u->port;
     ifmissing = CURLUE_NO_PORT;
-    urldecode = FALSE; /* never for port */
+    flags &= ~CURLU_URLDECODE; /* never for port */
     if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
       /* there is no stored port number, but asked to deliver
          a default one for the scheme */
@@ -1398,7 +1599,7 @@
   case CURLUPART_QUERY:
     ptr = u->query;
     ifmissing = CURLUE_NO_QUERY;
-    plusdecode = urldecode;
+    plusdecode = flags & CURLU_URLDECODE;
     if(ptr && !ptr[0] && !(flags & CURLU_GET_EMPTY))
       /* there was a blank query and the user do not ask for it */
       ptr = NULL;
@@ -1410,219 +1611,31 @@
       /* there was a blank fragment and the user asks for it */
       ptr = "";
     break;
-  case CURLUPART_URL: {
-    char *url;
-    const char *scheme;
-    char *options = u->options;
-    char *port = u->port;
-    char *allochost = NULL;
-    bool show_fragment =
-      u->fragment || (u->fragment_present && flags & CURLU_GET_EMPTY);
-    bool show_query =
-      (u->query && u->query[0]) ||
-      (u->query_present && flags & CURLU_GET_EMPTY);
-    punycode = (flags & CURLU_PUNYCODE) ? 1 : 0;
-    depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0;
-    if(u->scheme && strcasecompare("file", u->scheme)) {
-      url = aprintf("file://%s%s%s%s%s",
-                    u->path,
-                    show_query ? "?": "",
-                    u->query ? u->query : "",
-                    show_fragment ? "#": "",
-                    u->fragment ? u->fragment : "");
-    }
-    else if(!u->host)
-      return CURLUE_NO_HOST;
-    else {
-      const struct Curl_handler *h = NULL;
-      char schemebuf[MAX_SCHEME_LEN + 5];
-      if(u->scheme)
-        scheme = u->scheme;
-      else if(flags & CURLU_DEFAULT_SCHEME)
-        scheme = DEFAULT_SCHEME;
-      else
-        return CURLUE_NO_SCHEME;
-
-      h = Curl_get_scheme_handler(scheme);
-      if(!port && (flags & CURLU_DEFAULT_PORT)) {
-        /* there is no stored port number, but asked to deliver
-           a default one for the scheme */
-        if(h) {
-          msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
-          port = portbuf;
-        }
-      }
-      else if(port) {
-        /* there is a stored port number, but asked to inhibit if it matches
-           the default one for the scheme */
-        if(h && (h->defport == u->portnum) &&
-           (flags & CURLU_NO_DEFAULT_PORT))
-          port = NULL;
-      }
-
-      if(h && !(h->flags & PROTOPT_URLOPTIONS))
-        options = NULL;
-
-      if(u->host[0] == '[') {
-        if(u->zoneid) {
-          /* make it '[ host %25 zoneid ]' */
-          struct dynbuf enc;
-          size_t hostlen = strlen(u->host);
-          curlx_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
-          if(curlx_dyn_addf(&enc, "%.*s%%25%s]", (int)hostlen - 1, u->host,
-                            u->zoneid))
-            return CURLUE_OUT_OF_MEMORY;
-          allochost = curlx_dyn_ptr(&enc);
-        }
-      }
-      else if(urlencode) {
-        allochost = curl_easy_escape(NULL, u->host, 0);
-        if(!allochost)
-          return CURLUE_OUT_OF_MEMORY;
-      }
-      else if(punycode) {
-        if(!Curl_is_ASCII_name(u->host)) {
-#ifndef USE_IDN
-          return CURLUE_LACKS_IDN;
-#else
-          CURLcode result = Curl_idn_decode(u->host, &allochost);
-          if(result)
-            return (result == CURLE_OUT_OF_MEMORY) ?
-              CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
-#endif
-        }
-      }
-      else if(depunyfy) {
-        if(Curl_is_ASCII_name(u->host)) {
-#ifndef USE_IDN
-          return CURLUE_LACKS_IDN;
-#else
-          CURLcode result = Curl_idn_encode(u->host, &allochost);
-          if(result)
-            /* this is the most likely error */
-            return (result == CURLE_OUT_OF_MEMORY) ?
-              CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
-#endif
-        }
-      }
-
-      if(!(flags & CURLU_NO_GUESS_SCHEME) || !u->guessed_scheme)
-        msnprintf(schemebuf, sizeof(schemebuf), "%s://", scheme);
-      else
-        schemebuf[0] = 0;
-
-      url = aprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
-                    schemebuf,
-                    u->user ? u->user : "",
-                    u->password ? ":": "",
-                    u->password ? u->password : "",
-                    options ? ";" : "",
-                    options ? options : "",
-                    (u->user || u->password || options) ? "@": "",
-                    allochost ? allochost : u->host,
-                    port ? ":": "",
-                    port ? port : "",
-                    u->path ? u->path : "/",
-                    show_query ? "?": "",
-                    u->query ? u->query : "",
-                    show_fragment ? "#": "",
-                    u->fragment ? u->fragment : "");
-      free(allochost);
-    }
-    if(!url)
-      return CURLUE_OUT_OF_MEMORY;
-    *part = url;
-    return CURLUE_OK;
-  }
+  case CURLUPART_URL:
+    return urlget_url(u, part, flags);
   default:
     ptr = NULL;
     break;
   }
-  if(ptr) {
-    size_t partlen = strlen(ptr);
-    size_t i = 0;
-    *part = Curl_memdup0(ptr, partlen);
-    if(!*part)
-      return CURLUE_OUT_OF_MEMORY;
-    if(plusdecode) {
-      /* convert + to space */
-      char *plus = *part;
-      for(i = 0; i < partlen; ++plus, i++) {
-        if(*plus == '+')
-          *plus = ' ';
-      }
-    }
-    if(urldecode) {
-      char *decoded;
-      size_t dlen;
-      /* this unconditional rejection of control bytes is documented
-         API behavior */
-      CURLcode res = Curl_urldecode(*part, 0, &decoded, &dlen, REJECT_CTRL);
-      free(*part);
-      if(res) {
-        *part = NULL;
-        return CURLUE_URLDECODE;
-      }
-      *part = decoded;
-      partlen = dlen;
-    }
-    if(urlencode) {
-      struct dynbuf enc;
-      CURLUcode uc;
-      curlx_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
-      uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY);
-      if(uc)
-        return uc;
-      free(*part);
-      *part = curlx_dyn_ptr(&enc);
-    }
-    else if(punycode) {
-      if(!Curl_is_ASCII_name(u->host)) {
-#ifndef USE_IDN
-        return CURLUE_LACKS_IDN;
-#else
-        char *allochost;
-        CURLcode result = Curl_idn_decode(*part, &allochost);
-        if(result)
-          return (result == CURLE_OUT_OF_MEMORY) ?
-            CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
-        free(*part);
-        *part = allochost;
-#endif
-      }
-    }
-    else if(depunyfy) {
-      if(Curl_is_ASCII_name(u->host)) {
-#ifndef USE_IDN
-        return CURLUE_LACKS_IDN;
-#else
-        char *allochost;
-        CURLcode result = Curl_idn_encode(*part, &allochost);
-        if(result)
-          return (result == CURLE_OUT_OF_MEMORY) ?
-            CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
-        free(*part);
-        *part = allochost;
-#endif
-      }
-    }
+  if(ptr)
+    return urlget_format(u, what, ptr, part, plusdecode, flags);
 
-    return CURLUE_OK;
-  }
-  else
-    return ifmissing;
+  return ifmissing;
 }
 
 static CURLUcode set_url_scheme(CURLU *u, const char *scheme,
-        unsigned int flags)
+                                unsigned int flags)
 {
-    size_t plen = strlen(scheme);
+  size_t plen = strlen(scheme);
+  const struct Curl_handler *h = NULL;
+  if((plen > MAX_SCHEME_LEN) || (plen < 1))
+    /* too long or too short */
+    return CURLUE_BAD_SCHEME;
+  /* verify that it is a fine scheme */
+  h = Curl_get_scheme_handler(scheme);
+  if(!h) {
     const char *s = scheme;
-    if((plen > MAX_SCHEME_LEN) || (plen < 1))
-      /* too long or too short */
-      return CURLUE_BAD_SCHEME;
-   /* verify that it is a fine scheme */
-    if(!(flags & CURLU_NON_SUPPORT_SCHEME) && !Curl_get_scheme_handler(scheme))
+    if(!(flags & CURLU_NON_SUPPORT_SCHEME))
       return CURLUE_UNSUPPORTED_SCHEME;
     if(ISALPHA(*s)) {
       /* ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */
@@ -1635,8 +1648,9 @@
     }
     else
       return CURLUE_BAD_SCHEME;
-    u->guessed_scheme = FALSE;
-    return CURLUE_OK;
+  }
+  u->guessed_scheme = FALSE;
+  return CURLUE_OK;
 }
 
 static CURLUcode set_url_port(CURLU *u, const char *provided_port)
@@ -1659,7 +1673,7 @@
 }
 
 static CURLUcode set_url(CURLU *u, const char *url, size_t part_size,
-        unsigned int flags)
+                         unsigned int flags)
 {
   /*
    * Allow a new URL to replace the existing (if any) contents.
@@ -1696,6 +1710,53 @@
   return uc;
 }
 
+static CURLUcode urlset_clear(CURLU *u, CURLUPart what)
+{
+  switch(what) {
+  case CURLUPART_URL:
+    free_urlhandle(u);
+    memset(u, 0, sizeof(struct Curl_URL));
+    break;
+  case CURLUPART_SCHEME:
+    Curl_safefree(u->scheme);
+    u->guessed_scheme = FALSE;
+    break;
+  case CURLUPART_USER:
+    Curl_safefree(u->user);
+    break;
+  case CURLUPART_PASSWORD:
+    Curl_safefree(u->password);
+    break;
+  case CURLUPART_OPTIONS:
+    Curl_safefree(u->options);
+    break;
+  case CURLUPART_HOST:
+    Curl_safefree(u->host);
+    break;
+  case CURLUPART_ZONEID:
+    Curl_safefree(u->zoneid);
+    break;
+  case CURLUPART_PORT:
+    u->portnum = 0;
+    Curl_safefree(u->port);
+    break;
+  case CURLUPART_PATH:
+    Curl_safefree(u->path);
+    break;
+  case CURLUPART_QUERY:
+    Curl_safefree(u->query);
+    u->query_present = FALSE;
+    break;
+  case CURLUPART_FRAGMENT:
+    Curl_safefree(u->fragment);
+    u->fragment_present = FALSE;
+    break;
+  default:
+    return CURLUE_UNKNOWN_PART;
+  }
+  return CURLUE_OK;
+}
+
 CURLUcode curl_url_set(CURLU *u, CURLUPart what,
                        const char *part, unsigned int flags)
 {
@@ -1710,57 +1771,9 @@
 
   if(!u)
     return CURLUE_BAD_HANDLE;
-  if(!part) {
+  if(!part)
     /* setting a part to NULL clears it */
-    switch(what) {
-    case CURLUPART_URL:
-      break;
-    case CURLUPART_SCHEME:
-      storep = &u->scheme;
-      u->guessed_scheme = FALSE;
-      break;
-    case CURLUPART_USER:
-      storep = &u->user;
-      break;
-    case CURLUPART_PASSWORD:
-      storep = &u->password;
-      break;
-    case CURLUPART_OPTIONS:
-      storep = &u->options;
-      break;
-    case CURLUPART_HOST:
-      storep = &u->host;
-      break;
-    case CURLUPART_ZONEID:
-      storep = &u->zoneid;
-      break;
-    case CURLUPART_PORT:
-      u->portnum = 0;
-      storep = &u->port;
-      break;
-    case CURLUPART_PATH:
-      storep = &u->path;
-      break;
-    case CURLUPART_QUERY:
-      storep = &u->query;
-      u->query_present = FALSE;
-      break;
-    case CURLUPART_FRAGMENT:
-      storep = &u->fragment;
-      u->fragment_present = FALSE;
-      break;
-    default:
-      return CURLUE_UNKNOWN_PART;
-    }
-    if(storep && *storep) {
-      Curl_safefree(*storep);
-    }
-    else if(!storep) {
-      free_urlhandle(u);
-      memset(u, 0, sizeof(struct Curl_URL));
-    }
-    return CURLUE_OK;
-  }
+    return urlset_clear(u, what);
 
   nalloc = strlen(part);
   if(nalloc > CURL_MAX_INPUT_LENGTH)
@@ -1810,9 +1823,8 @@
     storep = &u->fragment;
     u->fragment_present = TRUE;
     break;
-  case CURLUPART_URL: {
+  case CURLUPART_URL:
     return set_url(u, part, nalloc, flags);
-  }
   default:
     return CURLUE_UNKNOWN_PART;
   }
@@ -1849,7 +1861,7 @@
         }
         else {
           unsigned char out[3]={'%'};
-          Curl_hexbyte(&out[1], *i, TRUE);
+          Curl_hexbyte(&out[1], *i);
           result = curlx_dyn_addn(&enc, out, 3);
           if(result)
             return cc2cu(result);
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index 45052e8..e54721d 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -158,20 +158,20 @@
 #include "request.h"
 #include "netrc.h"
 
-/* return the count of bytes sent, or -1 on error */
-typedef ssize_t (Curl_send)(struct Curl_easy *data,   /* transfer */
-                            int sockindex,            /* socketindex */
-                            const void *buf,          /* data to write */
-                            size_t len,               /* max amount to write */
-                            bool eos,                 /* last chunk */
-                            CURLcode *err);           /* error to return */
+/* On error return, the value of `pnwritten` has no meaning */
+typedef CURLcode (Curl_send)(struct Curl_easy *data,   /* transfer */
+                             int sockindex,            /* socketindex */
+                             const void *buf,          /* data to write */
+                             size_t len,               /* amount to send */
+                             bool eos,                 /* last chunk */
+                             size_t *pnwritten);       /* how much sent */
 
-/* return the count of bytes read, or -1 on error */
-typedef ssize_t (Curl_recv)(struct Curl_easy *data,   /* transfer */
-                            int sockindex,            /* socketindex */
-                            char *buf,                /* store data here */
-                            size_t len,               /* max amount to read */
-                            CURLcode *err);           /* error to return */
+/* On error return, the value of `pnread` has no meaning */
+typedef CURLcode (Curl_recv)(struct Curl_easy *data,   /* transfer */
+                             int sockindex,            /* socketindex */
+                             char *buf,                /* store data here */
+                             size_t len,               /* max amount to read */
+                             size_t *pnread);          /* how much received */
 
 #include "mime.h"
 #include "imap.h"
@@ -295,7 +295,6 @@
   char *key_type; /* format for private key (default: PEM) */
   char *key_passwd; /* plain text private key password */
   BIT(certinfo);     /* gather lots of certificate info */
-  BIT(falsestart);
   BIT(earlydata);    /* use tls1.3 early data */
   BIT(enable_beast); /* allow this flaw for interoperability's sake */
   BIT(no_revoke);    /* disable SSL certificate revocation checks */
@@ -357,93 +356,6 @@
   GSS_AUTHSUCC
 } curlnegotiate;
 
-/* Struct used for GSSAPI (Kerberos V5) authentication */
-#if defined(USE_KERBEROS5)
-struct kerberos5data {
-#if defined(USE_WINDOWS_SSPI)
-  CredHandle *credentials;
-  CtxtHandle *context;
-  TCHAR *spn;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  size_t token_max;
-  BYTE *output_token;
-#else
-  gss_ctx_id_t context;
-  gss_name_t spn;
-#endif
-};
-#endif
-
-/* Struct used for SCRAM-SHA-1 authentication */
-#ifdef USE_GSASL
-#include <gsasl.h>
-struct gsasldata {
-  Gsasl *ctx;
-  Gsasl_session *client;
-};
-#endif
-
-/* Struct used for NTLM challenge-response authentication */
-#if defined(USE_NTLM)
-struct ntlmdata {
-#ifdef USE_WINDOWS_SSPI
-/* The sslContext is used for the Schannel bindings. The
- * api is available on the Windows 7 SDK and later.
- */
-#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
-  CtxtHandle *sslContext;
-#endif
-  CredHandle *credentials;
-  CtxtHandle *context;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  size_t token_max;
-  BYTE *output_token;
-  BYTE *input_token;
-  size_t input_token_len;
-  TCHAR *spn;
-#else
-  unsigned int flags;
-  unsigned char nonce[8];
-  unsigned int target_info_len;
-  void *target_info; /* TargetInfo received in the NTLM type-2 message */
-#endif
-};
-#endif
-
-/* Struct used for Negotiate (SPNEGO) authentication */
-#ifdef USE_SPNEGO
-struct negotiatedata {
-#ifdef HAVE_GSSAPI
-  OM_uint32 status;
-  gss_ctx_id_t context;
-  gss_name_t spn;
-  gss_buffer_desc output_token;
-  struct dynbuf channel_binding_data;
-#else
-#ifdef USE_WINDOWS_SSPI
-#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
-  CtxtHandle *sslContext;
-#endif
-  DWORD status;
-  CredHandle *credentials;
-  CtxtHandle *context;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  TCHAR *spn;
-  size_t token_max;
-  BYTE *output_token;
-  size_t output_token_length;
-#endif
-#endif
-  BIT(noauthpersist);
-  BIT(havenoauthpersist);
-  BIT(havenegdata);
-  BIT(havemultiplerequests);
-};
-#endif
-
 #ifdef CURL_DISABLE_PROXY
 #define CONN_IS_PROXIED(x) 0
 #else
@@ -753,10 +665,6 @@
    * the connection is cleaned up (see Curl_hash_add2()).*/
   struct Curl_hash meta_hash;
 
-  /* 'remote_addr' is the particular IP we connected to. it is owned, set
-   * and NULLed by the connected socket filter (if there is one). */
-  const struct Curl_sockaddr_ex *remote_addr;
-
   struct hostname host;
   char *hostname_resolve; /* hostname to resolve to address, allocated */
   char *secondaryhostname; /* secondary socket hostname (ftp) */
@@ -788,7 +696,7 @@
   struct Curl_cfilter *cfilter[2]; /* connection filters */
   struct {
     struct curltime start[2]; /* when filter shutdown started */
-    unsigned int timeout_ms; /* 0 means no timeout */
+    timediff_t timeout_ms; /* 0 means no timeout */
   } shutdown;
 
   struct ssl_primary_config ssl_config;
@@ -823,10 +731,6 @@
   struct sockaddr_in local_addr;
 #endif
 
-#if defined(USE_KERBEROS5)    /* Consider moving some of the above GSS-API */
-  struct kerberos5data krb5;  /* variables into the structure definition, */
-#endif                        /* however, some of them are ftp specific. */
-
   struct uint_spbset xfers_attached; /* mids of attached transfers */
   /* A connection cache from a SHARE might be used in several multi handles.
    * We MUST not reuse connections that are running in another multi,
@@ -841,26 +745,14 @@
   CtxtHandle *sslContext;
 #endif
 
-#ifdef USE_GSASL
-  struct gsasldata gsasl;
-#endif
-
 #if defined(USE_NTLM)
   curlntlm http_ntlm_state;
   curlntlm proxy_ntlm_state;
-
-  struct ntlmdata ntlm;     /* NTLM differs from other authentication schemes
-                               because it authenticates connections, not
-                               single requests! */
-  struct ntlmdata proxyntlm; /* NTLM data for proxy */
 #endif
 
 #ifdef USE_SPNEGO
   curlnegotiate http_negotiate_state;
   curlnegotiate proxy_negotiate_state;
-
-  struct negotiatedata negotiate; /* state data for host Negotiate auth */
-  struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
 #endif
 
 #ifdef USE_UNIX_SOCKETS
@@ -893,7 +785,10 @@
 #ifndef CURL_DISABLE_PROXY
   unsigned char proxy_alpn; /* APLN of proxy tunnel, CURL_HTTP_VERSION* */
 #endif
-  unsigned char transport; /* one of the TRNSPRT_* defines */
+  unsigned char transport_wanted; /* one of the TRNSPRT_* defines. Not
+   necessarily the transport the connection ends using due to Alt-Svc
+   and happy eyeballing. Use `Curl_conn_get_transport() for actual value
+   once the connection is set up. */
   unsigned char ip_version; /* copied from the Curl_easy at creation time */
   /* HTTP version last responded with by the server.
    * 0 at start, then one of 09, 10, 11, etc. */
@@ -1263,9 +1158,6 @@
 #endif
   unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any)
                             is this */
-  unsigned char select_bits; /* != 0 -> bitmask of socket events for this
-                                 transfer overriding anything the socket may
-                                 report */
   unsigned int creds_from:2; /* where is the server credentials originating
                                 from, see the CREDS_* defines above */
 
@@ -1515,9 +1407,9 @@
 #endif
   void *progress_client; /* pointer to pass to the progress callback */
   void *ioctl_client;   /* pointer to pass to the ioctl callback */
-  long maxage_conn;     /* in seconds, max idle time to allow a connection that
+  timediff_t conn_max_idle_ms; /* max idle time to allow a connection that
                            is to be reused */
-  long maxlifetime_conn; /* in seconds, max time since creation to allow a
+  timediff_t conn_max_age_ms; /* max time since creation to allow a
                             connection that is to be reused */
 #ifndef CURL_DISABLE_TFTP
   long tftp_blksize;    /* in bytes, 0 means use default */
@@ -1563,7 +1455,7 @@
 #endif
   curl_off_t max_filesize; /* Maximum file size to download */
 #ifndef CURL_DISABLE_FTP
-  unsigned int accepttimeout;   /* in milliseconds, 0 means no timeout */
+  timediff_t accepttimeout;   /* in milliseconds, 0 means no timeout */
   unsigned char ftp_filemethod; /* how to get to a file: curl_ftpfile  */
   unsigned char ftpsslauth; /* what AUTH XXX to try: curl_ftpauth */
   unsigned char ftp_ccc;   /* FTP CCC options: curl_ftpccc */
@@ -1607,11 +1499,11 @@
   void *wildcardptr;
 #endif
 
-  unsigned int timeout;        /* ms, 0 means no timeout */
-  unsigned int connecttimeout; /* ms, 0 means default timeout */
-  unsigned int happy_eyeballs_timeout; /* ms, 0 is a valid value */
-  unsigned int server_response_timeout; /* ms, 0 means no timeout */
-  unsigned int shutdowntimeout; /* ms, 0 means default timeout */
+  timediff_t timeout;   /* ms, 0 means no timeout */
+  timediff_t connecttimeout; /* ms, 0 means default timeout */
+  timediff_t happy_eyeballs_timeout; /* ms, 0 is a valid value */
+  timediff_t server_response_timeout; /* ms, 0 means no timeout */
+  timediff_t shutdowntimeout; /* ms, 0 means default timeout */
   int tcp_keepidle;     /* seconds in idle before sending keepalive probe */
   int tcp_keepintvl;    /* seconds between TCP keepalive probes */
   int tcp_keepcnt;      /* maximum number of keepalive probes */
diff --git a/Utilities/cmcurl/lib/vauth/cleartext.c b/Utilities/cmcurl/lib/vauth/cleartext.c
index 719abd1..8fc5d41 100644
--- a/Utilities/cmcurl/lib/vauth/cleartext.c
+++ b/Utilities/cmcurl/lib/vauth/cleartext.c
@@ -127,7 +127,7 @@
  * Returns void.
  */
 void Curl_auth_create_external_message(const char *user,
-                                           struct bufref *out)
+                                       struct bufref *out)
 {
   /* This is the same formatting as the login message */
   Curl_auth_create_login_message(user, out);
diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
index ec4e822..898629a 100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/vauth/digest.c
@@ -42,7 +42,6 @@
 #include "../vtls/vtls.h"
 #include "../curlx/warnless.h"
 #include "../curlx/strparse.h"
-#include "../strcase.h"
 #include "../curl_printf.h"
 #include "../rand.h"
 
@@ -153,7 +152,7 @@
 
 /* Convert sha256 or SHA-512/256 chunk to RFC7616 -suitable ASCII string */
 static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
-                                     unsigned char *dest) /* 65 bytes */
+                                        unsigned char *dest) /* 65 bytes */
 {
   int i;
   for(i = 0; i < 32; i++)
@@ -510,31 +509,31 @@
 
     /* Extract a value=content pair */
     if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
-      if(strcasecompare(value, "nonce")) {
+      if(curl_strequal(value, "nonce")) {
         free(digest->nonce);
         digest->nonce = strdup(content);
         if(!digest->nonce)
           return CURLE_OUT_OF_MEMORY;
       }
-      else if(strcasecompare(value, "stale")) {
-        if(strcasecompare(content, "true")) {
+      else if(curl_strequal(value, "stale")) {
+        if(curl_strequal(content, "true")) {
           digest->stale = TRUE;
           digest->nc = 1; /* we make a new nonce now */
         }
       }
-      else if(strcasecompare(value, "realm")) {
+      else if(curl_strequal(value, "realm")) {
         free(digest->realm);
         digest->realm = strdup(content);
         if(!digest->realm)
           return CURLE_OUT_OF_MEMORY;
       }
-      else if(strcasecompare(value, "opaque")) {
+      else if(curl_strequal(value, "opaque")) {
         free(digest->opaque);
         digest->opaque = strdup(content);
         if(!digest->opaque)
           return CURLE_OUT_OF_MEMORY;
       }
-      else if(strcasecompare(value, "qop")) {
+      else if(curl_strequal(value, "qop")) {
         const char *token = content;
         struct Curl_str out;
         bool foundAuth = FALSE;
@@ -568,28 +567,28 @@
             return CURLE_OUT_OF_MEMORY;
         }
       }
-      else if(strcasecompare(value, "algorithm")) {
+      else if(curl_strequal(value, "algorithm")) {
         free(digest->algorithm);
         digest->algorithm = strdup(content);
         if(!digest->algorithm)
           return CURLE_OUT_OF_MEMORY;
 
-        if(strcasecompare(content, "MD5-sess"))
+        if(curl_strequal(content, "MD5-sess"))
           digest->algo = ALGO_MD5SESS;
-        else if(strcasecompare(content, "MD5"))
+        else if(curl_strequal(content, "MD5"))
           digest->algo = ALGO_MD5;
-        else if(strcasecompare(content, "SHA-256"))
+        else if(curl_strequal(content, "SHA-256"))
           digest->algo = ALGO_SHA256;
-        else if(strcasecompare(content, "SHA-256-SESS"))
+        else if(curl_strequal(content, "SHA-256-SESS"))
           digest->algo = ALGO_SHA256SESS;
-        else if(strcasecompare(content, "SHA-512-256")) {
+        else if(curl_strequal(content, "SHA-512-256")) {
 #ifdef CURL_HAVE_SHA512_256
           digest->algo = ALGO_SHA512_256;
 #else  /* ! CURL_HAVE_SHA512_256 */
           return CURLE_NOT_BUILT_IN;
 #endif /* ! CURL_HAVE_SHA512_256 */
         }
-        else if(strcasecompare(content, "SHA-512-256-SESS")) {
+        else if(curl_strequal(content, "SHA-512-256-SESS")) {
 #ifdef CURL_HAVE_SHA512_256
           digest->algo = ALGO_SHA512_256SESS;
 #else  /* ! CURL_HAVE_SHA512_256 */
@@ -599,8 +598,8 @@
         else
           return CURLE_BAD_CONTENT_ENCODING;
       }
-      else if(strcasecompare(value, "userhash")) {
-        if(strcasecompare(content, "true")) {
+      else if(curl_strequal(value, "userhash")) {
+        if(curl_strequal(content, "true")) {
           digest->userhash = TRUE;
         }
       }
@@ -771,7 +770,7 @@
   if(!hashthis)
     return CURLE_OUT_OF_MEMORY;
 
-  if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
+  if(digest->qop && curl_strequal(digest->qop, "auth-int")) {
     /* We do not support auth-int for PUT or POST */
     char hashed[65];
     char *hashthis2;
diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c
index 2761c59..28d0b35 100644
--- a/Utilities/cmcurl/lib/vauth/digest_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c
@@ -270,7 +270,7 @@
 
       /* Extract a value=content pair */
       if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
-        if(strcasecompare(value, "realm")) {
+        if(curl_strequal(value, "realm")) {
 
           /* Setup identity's domain and length */
           domain.tchar_ptr = curlx_convert_UTF8_to_tchar(content);
@@ -345,8 +345,8 @@
       if(!Curl_auth_digest_get_pair(p, value, content, &p))
         break;
 
-      if(strcasecompare(value, "stale") &&
-         strcasecompare(content, "true")) {
+      if(curl_strequal(value, "stale") &&
+         curl_strequal(content, "true")) {
         stale = TRUE;
         break;
       }
diff --git a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
index b559040..78f4be3 100644
--- a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
@@ -96,7 +96,6 @@
   OM_uint32 major_status;
   OM_uint32 minor_status;
   OM_uint32 unused_status;
-  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
 
@@ -104,6 +103,8 @@
   (void) passwdp;
 
   if(!krb5->spn) {
+    gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
+
     /* Generate our SPN */
     char *spn = Curl_auth_build_spn(service, NULL, host);
     if(!spn)
@@ -315,7 +316,8 @@
 
   /* Free our security context */
   if(krb5->context != GSS_C_NO_CONTEXT) {
-    gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER);
+    Curl_gss_delete_sec_context(&minor_status, &krb5->context,
+                                GSS_C_NO_BUFFER);
     krb5->context = GSS_C_NO_CONTEXT;
   }
 
diff --git a/Utilities/cmcurl/lib/vauth/oauth2.c b/Utilities/cmcurl/lib/vauth/oauth2.c
index 76e77c6..a84dc60 100644
--- a/Utilities/cmcurl/lib/vauth/oauth2.c
+++ b/Utilities/cmcurl/lib/vauth/oauth2.c
@@ -94,8 +94,8 @@
  * Returns CURLE_OK on success.
  */
 CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
-                                               const char *bearer,
-                                               struct bufref *out)
+                                                const char *bearer,
+                                                struct bufref *out)
 {
   /* Generate the message */
   char *xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
diff --git a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
index b17ee46..1e576c7 100644
--- a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
+++ b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
@@ -93,7 +93,6 @@
   OM_uint32 major_status;
   OM_uint32 minor_status;
   OM_uint32 unused_status;
-  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
   gss_channel_bindings_t chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
@@ -111,6 +110,8 @@
   }
 
   if(!nego->spn) {
+    gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
+
     /* Generate our SPN */
     char *spn = Curl_auth_build_spn(service, NULL, host);
     if(!spn)
@@ -267,7 +268,8 @@
 
   /* Free our security context */
   if(nego->context != GSS_C_NO_CONTEXT) {
-    gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER);
+    Curl_gss_delete_sec_context(&minor_status, &nego->context,
+                                GSS_C_NO_BUFFER);
     nego->context = GSS_C_NO_CONTEXT;
   }
 
@@ -276,7 +278,6 @@
     gss_release_buffer(&minor_status, &nego->output_token);
     nego->output_token.value = NULL;
     nego->output_token.length = 0;
-
   }
 
   /* Free the SPN */
diff --git a/Utilities/cmcurl/lib/vauth/vauth.c b/Utilities/cmcurl/lib/vauth/vauth.c
index e2872b2..7a85b70 100644
--- a/Utilities/cmcurl/lib/vauth/vauth.c
+++ b/Utilities/cmcurl/lib/vauth/vauth.c
@@ -27,10 +27,11 @@
 #include <curl/curl.h>
 
 #include "vauth.h"
+#include "../strdup.h"
 #include "../urldata.h"
-#include "../strcase.h"
 #include "../curlx/multibyte.h"
 #include "../curl_printf.h"
+#include "../url.h"
 
 /* The last #include files should be: */
 #include "../curl_memory.h"
@@ -156,7 +157,121 @@
   return !data->state.this_is_a_follow ||
          data->set.allow_auth_to_other_hosts ||
          (data->state.first_host &&
-          strcasecompare(data->state.first_host, conn->host.name) &&
+          curl_strequal(data->state.first_host, conn->host.name) &&
           (data->state.first_remote_port == conn->remote_port) &&
           (data->state.first_remote_protocol == conn->handler->protocol));
 }
+
+#ifdef USE_NTLM
+
+static void ntlm_conn_dtor(void *key, size_t klen, void *entry)
+{
+  struct ntlmdata *ntlm = entry;
+  (void)key;
+  (void)klen;
+  DEBUGASSERT(ntlm);
+  Curl_auth_cleanup_ntlm(ntlm);
+  free(ntlm);
+}
+
+struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy)
+{
+  const char *key = proxy ? CURL_META_NTLM_PROXY_CONN :
+                    CURL_META_NTLM_CONN;
+  struct ntlmdata *ntlm = Curl_conn_meta_get(conn, key);
+  if(!ntlm) {
+    ntlm = calloc(1, sizeof(*ntlm));
+    if(!ntlm ||
+       Curl_conn_meta_set(conn, key, ntlm, ntlm_conn_dtor))
+      return NULL;
+  }
+  return ntlm;
+}
+
+void Curl_auth_ntlm_remove(struct connectdata *conn, bool proxy)
+{
+  Curl_conn_meta_remove(conn, proxy ?
+    CURL_META_NTLM_PROXY_CONN : CURL_META_NTLM_CONN);
+}
+
+#endif /* USE_NTLM */
+
+#ifdef USE_KERBEROS5
+
+static void krb5_conn_dtor(void *key, size_t klen, void *entry)
+{
+  struct kerberos5data *krb5 = entry;
+  (void)key;
+  (void)klen;
+  DEBUGASSERT(krb5);
+  Curl_auth_cleanup_gssapi(krb5);
+  free(krb5);
+}
+
+struct kerberos5data *Curl_auth_krb5_get(struct connectdata *conn)
+{
+  struct kerberos5data *krb5 = Curl_conn_meta_get(conn, CURL_META_KRB5_CONN);
+  if(!krb5) {
+    krb5 = calloc(1, sizeof(*krb5));
+    if(!krb5 ||
+       Curl_conn_meta_set(conn, CURL_META_KRB5_CONN, krb5, krb5_conn_dtor))
+      return NULL;
+  }
+  return krb5;
+}
+
+#endif /* USE_KERBEROS5 */
+
+#ifdef USE_GSASL
+
+static void gsasl_conn_dtor(void *key, size_t klen, void *entry)
+{
+  struct gsasldata *gsasl = entry;
+  (void)key;
+  (void)klen;
+  DEBUGASSERT(gsasl);
+  Curl_auth_gsasl_cleanup(gsasl);
+  free(gsasl);
+}
+
+struct gsasldata *Curl_auth_gsasl_get(struct connectdata *conn)
+{
+  struct gsasldata *gsasl = Curl_conn_meta_get(conn, CURL_META_GSASL_CONN);
+  if(!gsasl) {
+    gsasl = calloc(1, sizeof(*gsasl));
+    if(!gsasl ||
+       Curl_conn_meta_set(conn, CURL_META_GSASL_CONN, gsasl, gsasl_conn_dtor))
+      return NULL;
+  }
+  return gsasl;
+}
+
+#endif /* USE_GSASL */
+
+#ifdef USE_SPNEGO
+
+static void nego_conn_dtor(void *key, size_t klen, void *entry)
+{
+  struct negotiatedata *nego = entry;
+  (void)key;
+  (void)klen;
+  DEBUGASSERT(nego);
+  Curl_auth_cleanup_spnego(nego);
+  free(nego);
+}
+
+struct negotiatedata *Curl_auth_nego_get(struct connectdata *conn, bool proxy)
+{
+  const char *key = proxy ? CURL_META_NEGO_PROXY_CONN :
+                    CURL_META_NEGO_CONN;
+  struct negotiatedata *nego = Curl_conn_meta_get(conn, key);
+  if(!nego) {
+    nego = calloc(1, sizeof(*nego));
+    if(!nego ||
+       Curl_conn_meta_set(conn, key, nego, nego_conn_dtor))
+      return NULL;
+  }
+  return nego;
+}
+
+#endif /* USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/vauth/vauth.h b/Utilities/cmcurl/lib/vauth/vauth.h
index 58b13f5..7d085e3 100644
--- a/Utilities/cmcurl/lib/vauth/vauth.h
+++ b/Utilities/cmcurl/lib/vauth/vauth.h
@@ -27,8 +27,10 @@
 #include <curl/curl.h>
 
 #include "../bufref.h"
+#include "../curlx/dynbuf.h"
 
 struct Curl_easy;
+struct connectdata;
 
 #if !defined(CURL_DISABLE_DIGEST_AUTH)
 struct digestdata;
@@ -38,10 +40,6 @@
 struct ntlmdata;
 #endif
 
-#if defined(USE_KERBEROS5)
-struct kerberos5data;
-#endif
-
 #if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO)
 struct negotiatedata;
 #endif
@@ -50,7 +48,8 @@
 struct gsasldata;
 #endif
 
-#if defined(USE_WINDOWS_SSPI)
+#ifdef USE_WINDOWS_SSPI
+#include "../curl_sspi.h"
 #define GSS_ERROR(status) ((status) & 0x80000000)
 #endif
 
@@ -117,9 +116,23 @@
 
 /* This is used to clean up the digest specific data */
 void Curl_auth_digest_cleanup(struct digestdata *digest);
+#else
+#define Curl_auth_is_digest_supported()       FALSE
 #endif /* !CURL_DISABLE_DIGEST_AUTH */
 
 #ifdef USE_GSASL
+
+/* meta key for storing GSASL meta at connection */
+#define CURL_META_GSASL_CONN   "meta:auth:gsasl:conn"
+
+#include <gsasl.h>
+struct gsasldata {
+  Gsasl *ctx;
+  Gsasl_session *client;
+};
+
+struct gsasldata *Curl_auth_gsasl_get(struct connectdata *conn);
+
 /* This is used to evaluate if MECH is supported by gsasl */
 bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
                                   const char *mech,
@@ -141,9 +154,46 @@
 #endif
 
 #if defined(USE_NTLM)
+
+/* meta key for storing NTML meta at connection */
+#define CURL_META_NTLM_CONN   "meta:auth:ntml:conn"
+/* meta key for storing NTML-PROXY meta at connection */
+#define CURL_META_NTLM_PROXY_CONN   "meta:auth:ntml-proxy:conn"
+
+struct ntlmdata {
+#ifdef USE_WINDOWS_SSPI
+/* The sslContext is used for the Schannel bindings. The
+ * api is available on the Windows 7 SDK and later.
+ */
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+  CtxtHandle *sslContext;
+#endif
+  CredHandle *credentials;
+  CtxtHandle *context;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  size_t token_max;
+  BYTE *output_token;
+  BYTE *input_token;
+  size_t input_token_len;
+  TCHAR *spn;
+#else
+  unsigned int flags;
+  unsigned char nonce[8];
+  unsigned int target_info_len;
+  void *target_info; /* TargetInfo received in the NTLM type-2 message */
+#endif
+};
+
 /* This is used to evaluate if NTLM is supported */
 bool Curl_auth_is_ntlm_supported(void);
 
+struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy);
+void Curl_auth_ntlm_remove(struct connectdata *conn, bool proxy);
+
+/* This is used to clean up the NTLM specific data */
+void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm);
+
 /* This is used to generate a base64 encoded NTLM type-1 message */
 CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
                                              const char *userp,
@@ -165,8 +215,6 @@
                                              struct ntlmdata *ntlm,
                                              struct bufref *out);
 
-/* This is used to clean up the NTLM specific data */
-void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm);
 #else
 #define Curl_auth_is_ntlm_supported()     FALSE
 #endif /* USE_NTLM */
@@ -184,6 +232,40 @@
                                                 struct bufref *out);
 
 #if defined(USE_KERBEROS5)
+
+#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSGNU
+#  include <gss.h>
+# elif defined HAVE_GSSAPI_GSSAPI_H
+#  include <gssapi/gssapi.h>
+# else
+#  include <gssapi.h>
+# endif
+# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H
+#  include <gssapi/gssapi_generic.h>
+# endif
+#endif
+
+/* meta key for storing KRB5 meta at connection */
+#define CURL_META_KRB5_CONN   "meta:auth:krb5:conn"
+
+struct kerberos5data {
+#if defined(USE_WINDOWS_SSPI)
+  CredHandle *credentials;
+  CtxtHandle *context;
+  TCHAR *spn;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  size_t token_max;
+  BYTE *output_token;
+#else
+  gss_ctx_id_t context;
+  gss_name_t spn;
+#endif
+};
+
+struct kerberos5data *Curl_auth_krb5_get(struct connectdata *conn);
+
 /* This is used to evaluate if GSSAPI (Kerberos V5) is supported */
 bool Curl_auth_is_gssapi_supported(void);
 
@@ -213,10 +295,48 @@
 #define Curl_auth_is_gssapi_supported()       FALSE
 #endif /* USE_KERBEROS5 */
 
-#if defined(USE_SPNEGO)
-/* This is used to evaluate if SPNEGO (Negotiate) is supported */
+#ifdef USE_SPNEGO
+
 bool Curl_auth_is_spnego_supported(void);
 
+/* meta key for storing NEGO meta at connection */
+#define CURL_META_NEGO_CONN         "meta:auth:nego:conn"
+/* meta key for storing NEGO PROXY meta at connection */
+#define CURL_META_NEGO_PROXY_CONN   "meta:auth:nego-proxy:conn"
+
+/* Struct used for Negotiate (SPNEGO) authentication */
+struct negotiatedata {
+#ifdef HAVE_GSSAPI
+  OM_uint32 status;
+  gss_ctx_id_t context;
+  gss_name_t spn;
+  gss_buffer_desc output_token;
+  struct dynbuf channel_binding_data;
+#else
+#ifdef USE_WINDOWS_SSPI
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+  CtxtHandle *sslContext;
+#endif
+  DWORD status;
+  CredHandle *credentials;
+  CtxtHandle *context;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  TCHAR *spn;
+  size_t token_max;
+  BYTE *output_token;
+  size_t output_token_length;
+#endif
+#endif
+  BIT(noauthpersist);
+  BIT(havenoauthpersist);
+  BIT(havenegdata);
+  BIT(havemultiplerequests);
+};
+
+struct negotiatedata *
+Curl_auth_nego_get(struct connectdata *conn, bool proxy);
+
 /* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge
    message */
 CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/vquic/curl_msh3.c b/Utilities/cmcurl/lib/vquic/curl_msh3.c
index cbeb650..6566447 100644
--- a/Utilities/cmcurl/lib/vquic/curl_msh3.c
+++ b/Utilities/cmcurl/lib/vquic/curl_msh3.c
@@ -83,16 +83,16 @@
 static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection,
                                           void *IfContext);
 static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
-                                          void *IfContext);
+                                                  void *IfContext);
 static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection,
-                                          void *IfContext,
-                                          MSH3_REQUEST *Request);
+                                            void *IfContext,
+                                            MSH3_REQUEST *Request);
 static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
                                            void *IfContext,
                                            const MSH3_HEADER *Header);
 static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
-                                        void *IfContext, uint32_t *Length,
-                                        const uint8_t *Data);
+                                         void *IfContext, uint32_t *Length,
+                                         const uint8_t *Data);
 static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
                                     bool Aborted, uint64_t AbortError);
 static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request,
@@ -244,33 +244,17 @@
 static void drain_stream_from_other_thread(struct Curl_easy *data,
                                            struct h3_stream_ctx *stream)
 {
-  unsigned char bits;
-
-  /* risky */
-  bits = CURL_CSELECT_IN;
-  if(stream && !stream->upload_done)
-    bits |= CURL_CSELECT_OUT;
-  if(data->state.select_bits != bits) {
-    data->state.select_bits = bits;
-    /* cannot expire from other thread */
-  }
+  (void)data;
+  (void)stream;
+  /* cannot expire from other thread.
+     here is the disconnect between msh3 and curl */
 }
 
 static void h3_drain_stream(struct Curl_cfilter *cf,
                             struct Curl_easy *data)
 {
-  struct cf_msh3_ctx *ctx = cf->ctx;
-  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  unsigned char bits;
-
   (void)cf;
-  bits = CURL_CSELECT_IN;
-  if(stream && !stream->upload_done)
-    bits |= CURL_CSELECT_OUT;
-  if(data->state.select_bits != bits) {
-    data->state.select_bits = bits;
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
-  }
+  Curl_multi_mark_dirty(data);
 }
 
 static const MSH3_CONNECTION_IF msh3_conn_if = {
@@ -294,7 +278,7 @@
 }
 
 static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
-                                          void *IfContext)
+                                                  void *IfContext)
 {
   struct Curl_cfilter *cf = IfContext;
   struct cf_msh3_ctx *ctx = cf->ctx;
@@ -307,8 +291,8 @@
 }
 
 static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection,
-                                          void *IfContext,
-                                          MSH3_REQUEST *Request)
+                                            void *IfContext,
+                                            MSH3_REQUEST *Request)
 {
   (void)Connection;
   (void)IfContext;
@@ -361,17 +345,16 @@
   struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
   CURLcode result = CURLE_OK;
-  ssize_t nwritten;
+  size_t nwritten;
 
   if(!stream)
     return CURLE_RECV_ERROR;
 
-  nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten);
+  if(result)
     return result;
-  }
 
-  if((size_t)nwritten < memlen) {
+  if(nwritten < memlen) {
     /* This MUST not happen. Our recbuf is dimensioned to hold the
      * full max_stream_window and then some for this very reason. */
     DEBUGASSERT(0);
@@ -518,40 +501,33 @@
   (void)SendContext;
 }
 
-static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  CURLcode *err)
+static CURLcode recv_closed_stream(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   size_t *pnread)
 {
   struct cf_msh3_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
 
-  if(!stream) {
-    *err = CURLE_RECV_ERROR;
-    return -1;
-  }
   (void)cf;
+  *pnread = 0;
+  if(!stream)
+    return CURLE_RECV_ERROR;
+
   if(stream->reset) {
     failf(data, "HTTP/3 stream reset by server");
-    *err = CURLE_PARTIAL_FILE;
-    CURL_TRC_CF(data, cf, "cf_recv, was reset -> %d", *err);
-    goto out;
+    CURL_TRC_CF(data, cf, "cf_recv, was reset");
+    return CURLE_PARTIAL_FILE;
   }
   else if(stream->error3) {
     failf(data, "HTTP/3 stream was not closed cleanly: (error %zd)",
           (ssize_t)stream->error3);
-    *err = CURLE_HTTP3;
-    CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly -> %d", *err);
-    goto out;
+    CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly");
+    return CURLE_HTTP3;
   }
   else {
-    CURL_TRC_CF(data, cf, "cf_recv, closed ok -> %d", *err);
+    CURL_TRC_CF(data, cf, "cf_recv, closed ok");
   }
-  *err = CURLE_OK;
-  nread = 0;
-
-out:
-  return nread;
+  return CURLE_OK;
 }
 
 static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -571,60 +547,56 @@
   }
 }
 
-static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                            char *buf, size_t len, CURLcode *err)
+static CURLcode cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                             char *buf, size_t len, size_t *pnread)
 {
   struct cf_msh3_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
   struct cf_call_data save;
+  CURLcode result = CURLE_OK;
 
+  *pnread = 0;
   CURL_TRC_CF(data, cf, "cf_recv(len=%zu), stream=%d", len, !!stream);
-  if(!stream) {
-    *err = CURLE_RECV_ERROR;
-    return -1;
-  }
+  if(!stream)
+    return CURLE_RECV_ERROR;
   CF_DATA_SAVE(save, cf, data);
 
   msh3_lock_acquire(&stream->recv_lock);
 
   if(stream->recv_error) {
     failf(data, "request aborted");
-    *err = stream->recv_error;
+    result = stream->recv_error;
     goto out;
   }
 
-  *err = CURLE_OK;
-
   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, err);
-    CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %zd, %d",
-                len, nread, *err);
-    if(nread < 0)
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
+    CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %d, %zu",
+                len, result, *pnread);
+    if(result)
       goto out;
     if(stream->closed)
       h3_drain_stream(cf, data);
   }
   else if(stream->closed) {
-    nread = recv_closed_stream(cf, data, err);
+    result = recv_closed_stream(cf, data, pnread);
     goto out;
   }
   else {
     CURL_TRC_CF(data, cf, "req: nothing here, call again");
-    *err = CURLE_AGAIN;
+    result = CURLE_AGAIN;
   }
 
 out:
   msh3_lock_release(&stream->recv_lock);
   set_quic_expire(cf, data);
   CF_DATA_RESTORE(cf, save);
-  return nread;
+  return result;
 }
 
-static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                            const void *buf, size_t len, bool eos,
-                            CURLcode *err)
+static CURLcode cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                             const void *buf, size_t len, bool eos,
+                             size_t *pnwritten)
 {
   struct cf_msh3_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -634,7 +606,9 @@
   size_t nheader, i;
   ssize_t nwritten = -1;
   struct cf_call_data save;
+  CURLcode result = CURLE_OK;
 
+  *pnwritten = 0;
   CF_DATA_SAVE(save, cf, data);
 
   Curl_h1_req_parse_init(&h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
@@ -648,23 +622,21 @@
     /* The first send on the request contains the headers and possibly some
        data. Parse out the headers and create the request, then if there is
        any data left over go ahead and send it too. */
-    nwritten = Curl_h1_req_parse_read(&h1, buf, len, NULL, 0, err);
+    nwritten = Curl_h1_req_parse_read(&h1, buf, len, NULL, 0, &result);
     if(nwritten < 0)
       goto out;
     DEBUGASSERT(h1.done);
     DEBUGASSERT(h1.req);
+    *pnwritten = (size_t)nwritten;
 
-    *err = Curl_http_req_to_h2(&h2_headers, h1.req, data);
-    if(*err) {
-      nwritten = -1;
+    result = Curl_http_req_to_h2(&h2_headers, h1.req, data);
+    if(result)
       goto out;
-    }
 
     nheader = Curl_dynhds_count(&h2_headers);
     nva = malloc(sizeof(MSH3_HEADER) * nheader);
     if(!nva) {
-      *err = CURLE_OUT_OF_MEMORY;
-      nwritten = -1;
+      result = CURLE_OUT_OF_MEMORY;
       goto out;
     }
 
@@ -683,11 +655,10 @@
                                   MSH3_REQUEST_FLAG_NONE);
     if(!stream->req) {
       failf(data, "request open failed");
-      *err = CURLE_SEND_ERROR;
-      goto out;
+      result = CURLE_SEND_ERROR;
     }
-    *err = CURLE_OK;
-    nwritten = len;
+    result = CURLE_OK;
+    *pnwritten = len;
     goto out;
   }
   else {
@@ -699,14 +670,14 @@
 
     if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_NONE, buf,
                         (uint32_t)len, stream)) {
-      *err = CURLE_SEND_ERROR;
+      result = CURLE_SEND_ERROR;
       goto out;
     }
 
     /* msh3/msquic will hold onto this memory until the send complete event.
        How do we make sure curl does not free it until then? */
-    *err = CURLE_OK;
-    nwritten = len;
+    result = CURLE_OK;
+    *pnwritten = len;
   }
 
 out:
@@ -715,7 +686,7 @@
   Curl_h1_req_parse_free(&h1);
   Curl_dynhds_free(&h2_headers);
   CF_DATA_RESTORE(cf, save);
-  return nwritten;
+  return result;
 }
 
 static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
@@ -964,8 +935,6 @@
                     "conn->sock[], discarding", (int)ctx->sock[SP_LOCAL]);
         ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
       }
-      if(cf->sockindex == FIRSTSOCKET)
-        cf->conn->remote_addr = NULL;
     }
     if(ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) {
       sclose(ctx->sock[SP_LOCAL]);
@@ -1049,7 +1018,6 @@
   cf_msh3_connect,
   cf_msh3_close,
   Curl_cf_def_shutdown,
-  Curl_cf_def_get_host,
   cf_msh3_adjust_pollset,
   cf_msh3_data_pending,
   cf_msh3_send,
diff --git a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
index f529f7e..69d54ec 100644
--- a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
+++ b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
@@ -47,12 +47,12 @@
 #endif
 
 #include "../urldata.h"
+#include "../url.h"
 #include "../uint-hash.h"
 #include "../sendf.h"
 #include "../strdup.h"
 #include "../rand.h"
 #include "../multiif.h"
-#include "../strcase.h"
 #include "../cfilters.h"
 #include "../cf-socket.h"
 #include "../connect.h"
@@ -342,23 +342,6 @@
   }
 }
 
-static void h3_drain_stream(struct Curl_cfilter *cf,
-                            struct Curl_easy *data)
-{
-  struct cf_ngtcp2_ctx *ctx = cf->ctx;
-  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  unsigned char bits;
-
-  (void)cf;
-  bits = CURL_CSELECT_IN;
-  if(stream && stream->upload_left && !stream->send_closed)
-    bits |= CURL_CSELECT_OUT;
-  if(data->state.select_bits != bits) {
-    data->state.select_bits = bits;
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
-  }
-}
-
 /* ngtcp2 default congestion controller does not perform pacing. Limit
    the maximum packet burst to MAX_PKT_BURST packets. */
 #define MAX_PKT_BURST 10
@@ -391,8 +374,8 @@
 }
 
 static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
-                                   uint64_t datalen, void *user_data,
-                                   void *stream_user_data);
+                                uint64_t datalen, void *user_data,
+                                void *stream_user_data);
 
 static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref)
 {
@@ -485,6 +468,7 @@
   ctx->handshake_at = curlx_now();
   ctx->tls_handshake_complete = TRUE;
   cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+  Curl_vquic_report_handshake(&ctx->tls, cf, data);
 
   ctx->tls_vrfy_result = Curl_vquic_tls_verify_peer(&ctx->tls, cf,
                                                     data, &ctx->peer);
@@ -744,7 +728,7 @@
     CURL_TRC_CF(s_data, cf, "[%" FMT_PRId64 "] unblock quic flow",
                 (curl_int64_t)stream_id);
     stream->quic_flow_blocked = FALSE;
-    h3_drain_stream(cf, s_data);
+    Curl_multi_mark_dirty(s_data);
   }
   return 0;
 }
@@ -912,8 +896,8 @@
 }
 
 static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
-                                      struct Curl_easy *data,
-                                      struct easy_pollset *ps)
+                                     struct Curl_easy *data,
+                                     struct easy_pollset *ps)
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
   bool want_recv, want_send;
@@ -971,7 +955,7 @@
   else {
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->id);
   }
-  h3_drain_stream(cf, data);
+  Curl_multi_mark_dirty(data);
   return 0;
 }
 
@@ -1072,7 +1056,7 @@
   if(stream->status_code / 100 != 1) {
     stream->resp_hds_complete = TRUE;
   }
-  h3_drain_stream(cf, data);
+  Curl_multi_mark_dirty(data);
   return 0;
 }
 
@@ -1293,14 +1277,14 @@
 }
 
 /* incoming data frames on the h3 stream */
-static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              char *buf, size_t blen, CURLcode *err)
+static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                               char *buf, size_t blen, size_t *pnread)
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
   struct cf_call_data save;
   struct pkt_io_ctx pktx;
+  CURLcode result = CURLE_OK;
 
   (void)ctx;
   (void)buf;
@@ -1310,7 +1294,7 @@
   DEBUGASSERT(ctx);
   DEBUGASSERT(ctx->qconn);
   DEBUGASSERT(ctx->h3conn);
-  *err = CURLE_OK;
+  *pnread = 0;
 
   /* handshake verification failed in callback, do not recv anything */
   if(ctx->tls_vrfy_result)
@@ -1319,46 +1303,38 @@
   pktx_init(&pktx, cf, data);
 
   if(!stream || ctx->shutdown_started) {
-    *err = CURLE_RECV_ERROR;
+    result = CURLE_RECV_ERROR;
     goto out;
   }
 
   if(cf_progress_ingress(cf, data, &pktx)) {
-    *err = CURLE_RECV_ERROR;
-    nread = -1;
+    result = CURLE_RECV_ERROR;
     goto out;
   }
 
   if(stream->xfer_result) {
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
     cf_ngtcp2_stream_close(cf, data, stream);
-    *err = stream->xfer_result;
-    nread = -1;
+    result = stream->xfer_result;
     goto out;
   }
   else if(stream->closed) {
-    nread = recv_closed_stream(cf, data, stream, err);
+    ssize_t nread = recv_closed_stream(cf, data, stream, &result);
+    if(nread > 0)
+      *pnread = (size_t)nread;
     goto out;
   }
-  *err = CURLE_AGAIN;
-  nread = -1;
+  result = CURLE_AGAIN;
 
 out:
-  if(cf_progress_egress(cf, data, &pktx)) {
-    *err = CURLE_SEND_ERROR;
-    nread = -1;
-  }
-  else {
-    CURLcode result2 = check_and_set_expiry(cf, data, &pktx);
-    if(result2) {
-      *err = result2;
-      nread = -1;
-    }
-  }
-  CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
-              stream ? stream->id : -1, blen, nread, *err);
+  result = Curl_1st_err(result, cf_progress_egress(cf, data, &pktx));
+  result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx));
+
+  CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %dm, %zu",
+
+              stream ? stream->id : -1, blen, result, *pnread);
   CF_DATA_RESTORE(cf, save);
-  return nread;
+  return result;
 }
 
 static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
@@ -1464,10 +1440,10 @@
    field list. */
 #define AUTHORITY_DST_IDX 3
 
-static ssize_t h3_stream_open(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              const void *buf, size_t len,
-                              CURLcode *err)
+static CURLcode h3_stream_open(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               const void *buf, size_t len,
+                               size_t *pnwritten)
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = NULL;
@@ -1480,41 +1456,43 @@
   ssize_t nwritten = -1;
   nghttp3_data_reader reader;
   nghttp3_data_reader *preader = NULL;
+  CURLcode result;
 
+  *pnwritten = 0;
   Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
 
-  *err = h3_data_setup(cf, data);
-  if(*err)
+  result = h3_data_setup(cf, data);
+  if(result)
     goto out;
   stream = H3_STREAM_CTX(ctx, data);
   DEBUGASSERT(stream);
   if(!stream) {
-    *err = CURLE_FAILED_INIT;
+    result = CURLE_FAILED_INIT;
     goto out;
   }
 
-  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
+  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result);
   if(nwritten < 0)
     goto out;
+  *pnwritten = (size_t)nwritten;
+
   if(!stream->h1.done) {
     /* need more data */
     goto out;
   }
   DEBUGASSERT(stream->h1.req);
 
-  *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
-  if(*err) {
-    nwritten = -1;
+  result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
+  if(result)
     goto out;
-  }
+
   /* no longer needed */
   Curl_h1_req_parse_free(&stream->h1);
 
   nheader = Curl_dynhds_count(&h2_headers);
   nva = malloc(sizeof(nghttp3_nv) * nheader);
   if(!nva) {
-    *err = CURLE_OUT_OF_MEMORY;
-    nwritten = -1;
+    result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
 
@@ -1530,8 +1508,7 @@
   rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, data);
   if(rc) {
     failf(data, "can get bidi streams");
-    *err = CURLE_SEND_ERROR;
-    nwritten = -1;
+    result = CURLE_SEND_ERROR;
     goto out;
   }
   stream->id = (curl_int64_t)sid;
@@ -1574,8 +1551,7 @@
                   "%d (%s)", stream->id, rc, nghttp3_strerror(rc));
       break;
     }
-    *err = CURLE_SEND_ERROR;
-    nwritten = -1;
+    result = CURLE_SEND_ERROR;
     goto out;
   }
 
@@ -1592,26 +1568,25 @@
 out:
   free(nva);
   Curl_dynhds_free(&h2_headers);
-  return nwritten;
+  return result;
 }
 
-static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              const void *buf, size_t len, bool eos,
-                              CURLcode *err)
+static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                               const void *buf, size_t len, bool eos,
+                               size_t *pnwritten)
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t sent = -1;
   struct cf_call_data save;
   struct pkt_io_ctx pktx;
-  CURLcode result;
+  CURLcode result = CURLE_OK;
 
   CF_DATA_SAVE(save, cf, data);
   DEBUGASSERT(cf->connected);
   DEBUGASSERT(ctx->qconn);
   DEBUGASSERT(ctx->h3conn);
   pktx_init(&pktx, cf, data);
-  *err = CURLE_OK;
+  *pnwritten = 0;
 
   /* handshake verification failed in callback, do not send anything */
   if(ctx->tls_vrfy_result)
@@ -1619,19 +1594,18 @@
 
   (void)eos; /* use for stream EOF and block handling */
   result = cf_progress_ingress(cf, data, &pktx);
-  if(result) {
-    *err = result;
-  }
+  if(result)
+    goto out;
 
   if(!stream || stream->id < 0) {
     if(ctx->shutdown_started) {
       CURL_TRC_CF(data, cf, "cannot open stream on closed connection");
-      *err = CURLE_SEND_ERROR;
+      result = CURLE_SEND_ERROR;
       goto out;
     }
-    sent = h3_stream_open(cf, data, buf, len, err);
-    if(sent < 0) {
-      CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
+    result = h3_stream_open(cf, data, buf, len, pnwritten);
+    if(result) {
+      CURL_TRC_CF(data, cf, "failed to open stream -> %d", result);
       goto out;
     }
     stream = H3_STREAM_CTX(ctx, data);
@@ -1639,7 +1613,7 @@
   else if(stream->xfer_result) {
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
     cf_ngtcp2_stream_close(cf, data, stream);
-    *err = stream->xfer_result;
+    result = stream->xfer_result;
     goto out;
   }
   else if(stream->closed) {
@@ -1651,52 +1625,43 @@
        * error situation. */
       CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data"
                   "on closed stream with response", stream->id);
-      *err = CURLE_OK;
-      sent = (ssize_t)len;
+      result = CURLE_OK;
+      *pnwritten = len;
       goto out;
     }
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) "
                 "-> stream closed", stream->id, len);
-    *err = CURLE_HTTP3;
-    sent = -1;
+    result = CURLE_HTTP3;
     goto out;
   }
   else if(ctx->shutdown_started) {
     CURL_TRC_CF(data, cf, "cannot send on closed connection");
-    *err = CURLE_SEND_ERROR;
+    result = CURLE_SEND_ERROR;
     goto out;
   }
   else {
-    sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
+    result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten);
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
-                "sendbuf(len=%zu) -> %zd, %d",
-                stream->id, len, sent, *err);
-    if(sent < 0) {
+                "sendbuf(len=%zu) -> %d, %zu",
+                stream->id, len, result, *pnwritten);
+    if(result)
       goto out;
-    }
-
     (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
   }
 
-  if(sent > 0 && !ctx->tls_handshake_complete && ctx->use_earlydata)
-    ctx->earlydata_skip += sent;
+  if(*pnwritten > 0 && !ctx->tls_handshake_complete && ctx->use_earlydata)
+    ctx->earlydata_skip += *pnwritten;
 
+  DEBUGASSERT(!result);
   result = cf_progress_egress(cf, data, &pktx);
-  if(result) {
-    *err = result;
-    sent = -1;
-  }
 
 out:
-  result = check_and_set_expiry(cf, data, &pktx);
-  if(result) {
-    *err = result;
-    sent = -1;
-  }
-  CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
-              stream ? stream->id : -1, len, sent, *err);
+  result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx));
+
+  CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %d, %zu",
+              stream ? stream->id : -1, len, result, *pnwritten);
   CF_DATA_RESTORE(cf, save);
-  return sent;
+  return result;
 }
 
 static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
@@ -1756,9 +1721,9 @@
  * Read a network packet to send from ngtcp2 into `buf`.
  * Return number of bytes written or -1 with *err set.
  */
-static ssize_t read_pkt_to_send(void *userp,
-                                unsigned char *buf, size_t buflen,
-                                CURLcode *err)
+static CURLcode read_pkt_to_send(void *userp,
+                                 unsigned char *buf, size_t buflen,
+                                 size_t *pnread)
 {
   struct pkt_io_ctx *x = userp;
   struct cf_ngtcp2_ctx *ctx = x->cf->ctx;
@@ -1768,7 +1733,9 @@
   uint32_t flags;
   int64_t stream_id;
   int fin;
-  ssize_t nwritten = 0, n;
+  ssize_t n;
+
+  *pnread = 0;
   veccnt = 0;
   stream_id = -1;
   fin = 0;
@@ -1780,7 +1747,6 @@
    * When ngtcp2 is happy (because it has no other frame that would fit
    * or it has nothing more to send), it returns the total length
    * of the assembled packet. This may be 0 if there was nothing to send. */
-  *err = CURLE_OK;
   for(;;) {
 
     if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) {
@@ -1790,8 +1756,7 @@
         failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
               nghttp3_strerror((int)veccnt));
         cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt);
-        *err = CURLE_SEND_ERROR;
-        return -1;
+        return CURLE_SEND_ERROR;
       }
     }
 
@@ -1803,9 +1768,7 @@
                                   (const ngtcp2_vec *)vec, veccnt, x->ts);
     if(n == 0) {
       /* nothing to send */
-      *err = CURLE_AGAIN;
-      nwritten = -1;
-      goto out;
+      return CURLE_AGAIN;
     }
     else if(n < 0) {
       switch(n) {
@@ -1837,9 +1800,7 @@
         failf(x->data, "ngtcp2_conn_writev_stream returned error: %s",
               ngtcp2_strerror((int)n));
         cf_ngtcp2_err_set(x->cf, x->data, (int)n);
-        *err = CURLE_SEND_ERROR;
-        nwritten = -1;
-        goto out;
+        return CURLE_SEND_ERROR;
       }
     }
 
@@ -1855,12 +1816,10 @@
 
     if(n > 0) {
       /* packet assembled, leave */
-      nwritten = n;
-      goto out;
+      *pnread = (size_t)n;
+      return CURLE_OK;
     }
   }
-out:
-  return nwritten;
 }
 
 static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
@@ -1868,7 +1827,7 @@
                                    struct pkt_io_ctx *pktx)
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
-  ssize_t nread;
+  size_t nread;
   size_t max_payload_size, path_max_payload_size, max_pktcnt;
   size_t pktcnt = 0;
   size_t gsolen = 0;  /* this disables gso until we have a clue */
@@ -1893,7 +1852,7 @@
     return curlcode;
   }
 
-  /* In UDP, there is a maximum theoretical packet paload length and
+  /* In UDP, there is a maximum theoretical packet payload length and
    * a minimum payload length that is "guaranteed" to work.
    * To detect if this minimum payload can be increased, ngtcp2 sends
    * now and then a packet payload larger than the minimum. It that
@@ -1913,9 +1872,9 @@
 
   for(;;) {
     /* add the next packet to send, if any, to our buffer */
-    nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
-                           read_pkt_to_send, pktx, &curlcode);
-    if(nread < 0) {
+    curlcode = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
+                              read_pkt_to_send, pktx, &nread);
+    if(curlcode) {
       if(curlcode != CURLE_AGAIN)
         return curlcode;
       /* Nothing more to add, flush and leave */
@@ -1934,10 +1893,10 @@
     if(pktcnt == 0) {
       /* first packet in buffer. This is either of a known, "good"
        * payload size or it is a PMTUD. We will see. */
-      gsolen = (size_t)nread;
+      gsolen = nread;
     }
-    else if((size_t)nread > gsolen ||
-            (gsolen > path_max_payload_size && (size_t)nread != gsolen)) {
+    else if(nread > gsolen ||
+            (gsolen > path_max_payload_size && nread != gsolen)) {
       /* The just added packet is a PMTUD *or* the one(s) before the
        * just added were PMTUD and the last one is smaller.
        * Flush the buffer before the last add. */
@@ -1954,7 +1913,7 @@
       continue;
     }
 
-    if(++pktcnt >= max_pktcnt || (size_t)nread < gsolen) {
+    if(++pktcnt >= max_pktcnt || nread < gsolen) {
       /* Reached MAX_PKT_BURST *or*
        * the capacity of our buffer *or*
        * last add was shorter than the previous ones, flush */
@@ -1975,28 +1934,15 @@
   return CURLE_OK;
 }
 
-/*
- * Called from transfer.c:data_pending to know if we should keep looping
- * to receive more data from the connection.
- */
-static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf,
-                                   const struct Curl_easy *data)
-{
-  (void)cf;
-  (void)data;
-  return FALSE;
-}
-
 static CURLcode h3_data_pause(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               bool pause)
 {
   /* There seems to exist no API in ngtcp2 to shrink/enlarge the streams
    * windows. As we do in HTTP/2. */
-  if(!pause) {
-    h3_drain_stream(cf, data);
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
-  }
+  (void)cf;
+  if(!pause)
+    Curl_multi_mark_dirty(data);
   return CURLE_OK;
 }
 
@@ -2129,8 +2075,9 @@
       /* Ignore amount written. sendbuf was empty and has always room for
        * NGTCP2_MAX_UDP_PAYLOAD_SIZE. It can only completely fail, in which
        * case `result` is set non zero. */
-      (void)Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
-                            (size_t)nwritten, &result);
+      size_t n;
+      result = Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
+                               (size_t)nwritten, &n);
       if(result) {
         CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, "
                     "aborting shutdown", result);
@@ -2702,6 +2649,14 @@
   case CF_QUERY_HTTP_VERSION:
     *pres1 = 30;
     return CURLE_OK;
+  case CF_QUERY_SSL_INFO:
+  case CF_QUERY_SSL_CTX_INFO: {
+    struct curl_tlssessioninfo *info = pres2;
+    if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+                                   (query == CF_QUERY_SSL_INFO), info))
+      return CURLE_OK;
+    break;
+  }
   default:
     break;
   }
@@ -2761,9 +2716,8 @@
   cf_ngtcp2_connect,
   cf_ngtcp2_close,
   cf_ngtcp2_shutdown,
-  Curl_cf_def_get_host,
   cf_ngtcp2_adjust_pollset,
-  cf_ngtcp2_data_pending,
+  Curl_cf_def_data_pending,
   cf_ngtcp2_send,
   cf_ngtcp2_recv,
   cf_ngtcp2_data_event,
diff --git a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.h b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.h
index 8846625..a4ccef4 100644
--- a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.h
+++ b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.h
@@ -52,9 +52,9 @@
 void Curl_ngtcp2_ver(char *p, size_t len);
 
 CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
-                             struct Curl_easy *data,
-                             struct connectdata *conn,
-                             const struct Curl_addrinfo *ai);
+                               struct Curl_easy *data,
+                               struct connectdata *conn,
+                               const struct Curl_addrinfo *ai);
 
 bool Curl_conn_is_ngtcp2(const struct Curl_easy *data,
                          const struct connectdata *conn,
diff --git a/Utilities/cmcurl/lib/vquic/curl_osslq.c b/Utilities/cmcurl/lib/vquic/curl_osslq.c
index d5af10b..90fed6c 100644
--- a/Utilities/cmcurl/lib/vquic/curl_osslq.c
+++ b/Utilities/cmcurl/lib/vquic/curl_osslq.c
@@ -37,7 +37,6 @@
 #include "../strdup.h"
 #include "../rand.h"
 #include "../multiif.h"
-#include "../strcase.h"
 #include "../cfilters.h"
 #include "../cf-socket.h"
 #include "../connect.h"
@@ -55,6 +54,7 @@
 #include "../vtls/vtls.h"
 #include "../vtls/openssl.h"
 #include "curl_osslq.h"
+#include "../url.h"
 #include "../curlx/warnless.h"
 
 /* The last 3 #include files should be in this order */
@@ -560,7 +560,7 @@
 }
 
 static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data)
+                                     struct Curl_easy *data)
 {
   struct cf_osslq_ctx *ctx = cf->ctx;
 
@@ -711,31 +711,14 @@
   return NULL;
 }
 
-static void h3_drain_stream(struct Curl_cfilter *cf,
-                            struct Curl_easy *data)
-{
-  struct cf_osslq_ctx *ctx = cf->ctx;
-  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  unsigned char bits;
-
-  (void)cf;
-  bits = CURL_CSELECT_IN;
-  if(stream && stream->upload_left && !stream->send_closed)
-    bits |= CURL_CSELECT_OUT;
-  if(data->state.select_bits != bits) {
-    data->state.select_bits = bits;
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
-  }
-}
-
 static CURLcode h3_data_pause(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               bool pause)
 {
+  (void)cf;
   if(!pause) {
     /* unpaused. make it run again right away */
-    h3_drain_stream(cf, data);
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+    Curl_multi_mark_dirty(data);
   }
   return CURLE_OK;
 }
@@ -766,7 +749,7 @@
   else {
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->s.id);
   }
-  h3_drain_stream(cf, data);
+  Curl_multi_mark_dirty(data);
   return 0;
 }
 
@@ -783,21 +766,20 @@
   struct cf_osslq_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
   CURLcode result = CURLE_OK;
-  ssize_t nwritten;
+  size_t nwritten;
 
   (void)cf;
   if(!stream) {
     return CURLE_RECV_ERROR;
   }
-  nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten);
+  if(result)
     return result;
-  }
 
   if(!flow)
     stream->recv_buf_nonflow += (size_t)nwritten;
 
-  if((size_t)nwritten < memlen) {
+  if(nwritten < memlen) {
     /* This MUST not happen. Our recbuf is dimensioned to hold the
      * full max_stream_window and then some for this very reason. */
     DEBUGASSERT(0);
@@ -831,7 +813,7 @@
   stream->download_recvd += (curl_off_t)buflen;
   CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, total=%" FMT_OFF_T,
               stream->s.id, buflen, stream->download_recvd);
-  h3_drain_stream(cf, data);
+  Curl_multi_mark_dirty(data);
   return 0;
 }
 
@@ -943,7 +925,7 @@
   if(stream->status_code / 100 != 1) {
     stream->resp_hds_complete = TRUE;
   }
-  h3_drain_stream(cf, data);
+  Curl_multi_mark_dirty(data);
   return 0;
 }
 
@@ -1259,27 +1241,24 @@
   struct cf_osslq_stream *s;
 };
 
-static ssize_t h3_quic_recv(void *reader_ctx,
-                            unsigned char *buf, size_t len,
-                            CURLcode *err)
+static CURLcode h3_quic_recv(void *reader_ctx,
+                             unsigned char *buf, size_t len,
+                             size_t *pnread)
 {
   struct h3_quic_recv_ctx *x = reader_ctx;
-  size_t nread;
   int rv;
 
-  *err = CURLE_OK;
-  rv = SSL_read_ex(x->s->ssl, buf, len, &nread);
+  rv = SSL_read_ex(x->s->ssl, buf, len, pnread);
   if(rv <= 0) {
     int detail = SSL_get_error(x->s->ssl, rv);
     if(detail == SSL_ERROR_WANT_READ || detail == SSL_ERROR_WANT_WRITE) {
-      *err = CURLE_AGAIN;
-      return -1;
+      return CURLE_AGAIN;
     }
     else if(detail == SSL_ERROR_ZERO_RETURN) {
       CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> EOS",
                   x->s->id);
       x->s->recvd_eos = TRUE;
-      return 0;
+      return CURLE_OK;
     }
     else if(SSL_get_stream_read_state(x->s->ssl) ==
             SSL_STREAM_STATE_RESET_REMOTE) {
@@ -1292,14 +1271,13 @@
         x->s->reset = TRUE;
       }
       x->s->recvd_eos = TRUE;
-      return 0;
+      return CURLE_OK;
     }
     else {
-      *err = cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR);
-      return -1;
+      return cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR);
     }
   }
-  return (ssize_t)nread;
+  return CURLE_OK;
 }
 
 static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
@@ -1309,6 +1287,7 @@
   struct cf_osslq_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
   ssize_t nread;
+  size_t n;
   struct h3_quic_recv_ctx x;
   bool eagain = FALSE;
   size_t total_recv_len = 0;
@@ -1324,8 +1303,8 @@
         (total_recv_len < H3_STREAM_CHUNK_SIZE)) {
     if(Curl_bufq_is_empty(&s->recvbuf) && !s->recvd_eos) {
       while(!eagain && !s->recvd_eos && !Curl_bufq_is_full(&s->recvbuf)) {
-        nread = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &result);
-        if(nread < 0) {
+        result = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &n);
+        if(result) {
           if(result != CURLE_AGAIN)
             goto out;
           result = CURLE_OK;
@@ -1566,7 +1545,7 @@
           if(stream) {
             nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
             stream->s.send_blocked = FALSE;
-            h3_drain_stream(cf, ctx->curl_items[idx_count]);
+            Curl_multi_mark_dirty(ctx->curl_items[idx_count]);
             CURL_TRC_CF(ctx->curl_items[idx_count], cf, "unblocked");
           }
           result_count--;
@@ -2009,44 +1988,39 @@
   return nwritten;
 }
 
-static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                             const void *buf, size_t len, bool eos,
-                             CURLcode *err)
+static CURLcode cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              const void *buf, size_t len, bool eos,
+                              size_t *pnwritten)
 {
   struct cf_osslq_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
   struct cf_call_data save;
   ssize_t nwritten;
-  CURLcode result;
+  CURLcode result = CURLE_OK;
 
   (void)eos; /* use to end stream */
   CF_DATA_SAVE(save, cf, data);
   DEBUGASSERT(cf->connected);
   DEBUGASSERT(ctx->tls.ossl.ssl);
   DEBUGASSERT(ctx->h3.conn);
-  *err = CURLE_OK;
+  *pnwritten = 0;
 
   result = cf_progress_ingress(cf, data);
-  if(result) {
-    *err = result;
-    nwritten = -1;
+  if(result)
     goto out;
-  }
 
   result = cf_progress_egress(cf, data);
-  if(result) {
-    *err = result;
-    nwritten = -1;
+  if(result)
     goto out;
-  }
 
   if(!stream || stream->s.id < 0) {
-    nwritten = h3_stream_open(cf, data, buf, len, err);
+    nwritten = h3_stream_open(cf, data, buf, len, &result);
     if(nwritten < 0) {
-      CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
+      CURL_TRC_CF(data, cf, "failed to open stream -> %d", result);
       goto out;
     }
     stream = H3_STREAM_CTX(ctx, data);
+    *pnwritten = (size_t)nwritten;
   }
   else if(stream->closed) {
     if(stream->resp_hds_complete) {
@@ -2057,56 +2031,48 @@
        * error situation. */
       CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data"
                   "on closed stream with response", stream->s.id);
-      *err = CURLE_OK;
-      nwritten = (ssize_t)len;
+      result = CURLE_OK;
+      *pnwritten = len;
       goto out;
     }
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) "
                 "-> stream closed", stream->s.id, len);
-    *err = CURLE_HTTP3;
-    nwritten = -1;
+    result = CURLE_HTTP3;
     goto out;
   }
   else {
-    nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
+    result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten);
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
-                "sendbuf(len=%zu) -> %zd, %d",
-                stream->s.id, len, nwritten, *err);
-    if(nwritten < 0) {
+                "sendbuf(len=%zu) -> %d, %zu",
+                stream->s.id, len, result, *pnwritten);
+    if(result)
       goto out;
-    }
-
     (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
   }
 
-  result = cf_progress_egress(cf, data);
-  if(result) {
-    *err = result;
-    nwritten = -1;
-  }
+  result = Curl_1st_err(result, cf_progress_egress(cf, data));
 
 out:
-  result = check_and_set_expiry(cf, data);
-  CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
-              stream ? stream->s.id : -1, len, nwritten, *err);
+  result = Curl_1st_err(result, check_and_set_expiry(cf, data));
+
+  CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %d, %zu",
+              stream ? stream->s.id : -1, len, result, *pnwritten);
   CF_DATA_RESTORE(cf, save);
-  return nwritten;
+  return result;
 }
 
-static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  struct h3_stream_ctx *stream,
-                                  CURLcode *err)
+static CURLcode recv_closed_stream(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   struct h3_stream_ctx *stream,
+                                   size_t *pnread)
 {
-  ssize_t nread = -1;
-
   (void)cf;
+  *pnread = 0;
   if(stream->reset) {
     failf(data,
           "HTTP/3 stream %" FMT_PRId64 " reset by server",
           stream->s.id);
-    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
-    goto out;
+    return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
   }
   else if(!stream->resp_hds_complete) {
     failf(data,
@@ -2114,24 +2080,18 @@
           " was closed cleanly, but before getting"
           " all response header fields, treated as error",
           stream->s.id);
-    *err = CURLE_HTTP3;
-    goto out;
+    return CURLE_HTTP3;
   }
-  *err = CURLE_OK;
-  nread = 0;
-
-out:
-  return nread;
+  return CURLE_OK;
 }
 
-static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                             char *buf, size_t len, CURLcode *err)
+static CURLcode cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              char *buf, size_t len, size_t *pnread)
 {
   struct cf_osslq_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
   struct cf_call_data save;
-  CURLcode result;
+  CURLcode result = CURLE_OK;
 
   (void)ctx;
   CF_DATA_SAVE(save, cf, data);
@@ -2139,69 +2099,55 @@
   DEBUGASSERT(ctx);
   DEBUGASSERT(ctx->tls.ossl.ssl);
   DEBUGASSERT(ctx->h3.conn);
-  *err = CURLE_OK;
+  *pnread = 0;
 
   if(!stream) {
-    *err = CURLE_RECV_ERROR;
+    result = CURLE_RECV_ERROR;
     goto out;
   }
 
   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, err);
-    if(nread < 0) {
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
+    if(result) {
       CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
-                  "-> %zd, %d", stream->s.id, len, nread, *err);
+                  "-> %d, %zu", stream->s.id, len, result, *pnread);
       goto out;
     }
   }
 
-  result = cf_progress_ingress(cf, data);
-  if(result) {
-    *err = result;
-    nread = -1;
+  result = Curl_1st_err(result, cf_progress_ingress(cf, data));
+  if(result)
     goto out;
-  }
 
   /* recvbuf had nothing before, maybe after progressing ingress? */
-  if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, err);
-    if(nread < 0) {
+  if(!*pnread && !Curl_bufq_is_empty(&stream->recvbuf)) {
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
+    if(result) {
       CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
-                  "-> %zd, %d", stream->s.id, len, nread, *err);
+                  "-> %d, %zu", stream->s.id, len, result, *pnread);
       goto out;
     }
   }
 
-  if(nread > 0) {
-    h3_drain_stream(cf, data);
+  if(*pnread) {
+    Curl_multi_mark_dirty(data);
   }
   else {
     if(stream->closed) {
-      nread = recv_closed_stream(cf, data, stream, err);
+      result = recv_closed_stream(cf, data, stream, pnread);
       goto out;
     }
-    *err = CURLE_AGAIN;
-    nread = -1;
+    result = CURLE_AGAIN;
   }
 
 out:
-  if(cf_progress_egress(cf, data)) {
-    *err = CURLE_SEND_ERROR;
-    nread = -1;
-  }
-  else {
-    CURLcode result2 = check_and_set_expiry(cf, data);
-    if(result2) {
-      *err = result2;
-      nread = -1;
-    }
-  }
-  CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %zd, %d",
-              stream ? stream->s.id : -1, len, nread, *err);
+  result = Curl_1st_err(result, cf_progress_egress(cf, data));
+  result = Curl_1st_err(result, check_and_set_expiry(cf, data));
+
+  CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %d, %zu",
+              stream ? stream->s.id : -1, len, result, *pnread);
   CF_DATA_RESTORE(cf, save);
-  return nread;
+  return result;
 }
 
 /*
@@ -2358,8 +2304,9 @@
   case CF_QUERY_MAX_CONCURRENT: {
 #ifdef SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL
     /* Added in OpenSSL v3.3.x */
-    uint64_t v;
-    if(!SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_GENERIC,
+    uint64_t v = 0;
+    if(ctx->tls.ossl.ssl &&
+       !SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_GENERIC,
                            SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL, &v)) {
       CURL_TRC_CF(data, cf, "error getting available local bidi streams");
       return CURLE_HTTP3;
@@ -2396,6 +2343,14 @@
   case CF_QUERY_HTTP_VERSION:
     *pres1 = 30;
     return CURLE_OK;
+  case CF_QUERY_SSL_INFO:
+  case CF_QUERY_SSL_CTX_INFO: {
+    struct curl_tlssessioninfo *info = pres2;
+    if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+                                   (query == CF_QUERY_SSL_INFO), info))
+      return CURLE_OK;
+    break;
+  }
   default:
     break;
   }
@@ -2412,7 +2367,6 @@
   cf_osslq_connect,
   cf_osslq_close,
   cf_osslq_shutdown,
-  Curl_cf_def_get_host,
   cf_osslq_adjust_pollset,
   cf_osslq_data_pending,
   cf_osslq_send,
diff --git a/Utilities/cmcurl/lib/vquic/curl_quiche.c b/Utilities/cmcurl/lib/vquic/curl_quiche.c
index 8806532..920913d 100644
--- a/Utilities/cmcurl/lib/vquic/curl_quiche.c
+++ b/Utilities/cmcurl/lib/vquic/curl_quiche.c
@@ -36,7 +36,6 @@
 #include "../sendf.h"
 #include "../strdup.h"
 #include "../rand.h"
-#include "../strcase.h"
 #include "../multiif.h"
 #include "../connect.h"
 #include "../progress.h"
@@ -47,6 +46,7 @@
 #include "vquic-tls.h"
 #include "curl_quiche.h"
 #include "../transfer.h"
+#include "../url.h"
 #include "../curlx/inet_pton.h"
 #include "../vtls/openssl.h"
 #include "../vtls/keylog.h"
@@ -237,7 +237,7 @@
   (void)user_data;
   if(stream->quic_flow_blocked) {
     stream->quic_flow_blocked = FALSE;
-    Curl_expire(sdata, 0, EXPIRE_RUN_NOW);
+    Curl_multi_mark_dirty(sdata);
     CURL_TRC_CF(sdata, cf, "[%"FMT_PRIu64"] unblock", stream->id);
   }
   return TRUE;
@@ -250,8 +250,8 @@
 {
   (void)stream;
   (void)user_data;
-  CURL_TRC_CF(sdata, cf, "conn closed, expire transfer");
-  Curl_expire(sdata, 0, EXPIRE_RUN_NOW);
+  CURL_TRC_CF(sdata, cf, "conn closed, mark as dirty");
+  Curl_multi_mark_dirty(sdata);
   return TRUE;
 }
 
@@ -307,23 +307,6 @@
   }
 }
 
-static void h3_drain_stream(struct Curl_cfilter *cf,
-                            struct Curl_easy *data)
-{
-  struct cf_quiche_ctx *ctx = cf->ctx;
-  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  unsigned char bits;
-
-  (void)cf;
-  bits = CURL_CSELECT_IN;
-  if(stream && !stream->send_closed)
-    bits |= CURL_CSELECT_OUT;
-  if(data->state.select_bits != bits) {
-    data->state.select_bits = bits;
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
-  }
-}
-
 static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf,
                                          struct Curl_easy *data)
 {
@@ -344,16 +327,16 @@
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
   CURLcode result = CURLE_OK;
-  ssize_t nwritten;
+  size_t nwritten;
 
   (void)cf;
   if(!stream)
     return CURLE_RECV_ERROR;
-  nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
-  if(nwritten < 0)
+  result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten);
+  if(result)
     return result;
 
-  if((size_t)nwritten < memlen) {
+  if(nwritten < memlen) {
     /* This MUST not happen. Our recbuf is dimensioned to hold the
      * full max_stream_window and then some for this very reason. */
     DEBUGASSERT(0);
@@ -407,30 +390,26 @@
   return result;
 }
 
-static ssize_t stream_resp_read(void *reader_ctx,
-                                unsigned char *buf, size_t len,
-                                CURLcode *err)
+static CURLcode stream_resp_read(void *reader_ctx,
+                                 unsigned char *buf, size_t len,
+                                 size_t *pnread)
 {
   struct cb_ctx *x = reader_ctx;
   struct cf_quiche_ctx *ctx = x->cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
   ssize_t nread;
 
-  if(!stream) {
-    *err = CURLE_RECV_ERROR;
-    return -1;
-  }
+  *pnread = 0;
+  if(!stream)
+    return CURLE_RECV_ERROR;
 
-  nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id,
-                              buf, len);
+  nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id, buf, len);
   if(nread >= 0) {
-    *err = CURLE_OK;
-    return nread;
+    *pnread = (size_t)nread;
+    return CURLE_OK;
   }
-  else {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
+  else
+    return CURLE_AGAIN;
 }
 
 static CURLcode cf_recv_body(struct Curl_cfilter *cf,
@@ -438,7 +417,7 @@
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nwritten;
+  size_t nread;
   struct cb_ctx cb_ctx;
   CURLcode result = CURLE_OK;
 
@@ -454,12 +433,12 @@
 
   cb_ctx.cf = cf;
   cb_ctx.data = data;
-  nwritten = Curl_bufq_slurp(&stream->recvbuf,
-                             stream_resp_read, &cb_ctx, &result);
+  result = Curl_bufq_slurp(&stream->recvbuf,
+                           stream_resp_read, &cb_ctx, &nread);
 
-  if(nwritten < 0 && result != CURLE_AGAIN) {
-    CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zd",
-                stream->id, nwritten);
+  if(result && result != CURLE_AGAIN) {
+    CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zu",
+                stream->id, nread);
     failf(data, "Error %d in HTTP/3 response body for stream[%"FMT_PRIu64"]",
           result, stream->id);
     stream->closed = TRUE;
@@ -562,7 +541,7 @@
                                      quiche_h3_event *ev)
 {
   CURLcode result = h3_process_event(cf, data, stream, ev);
-  h3_drain_stream(cf, data);
+  Curl_multi_mark_dirty(data);
   if(result)
     CURL_TRC_CF(data, cf, "error processing event %s "
                 "for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev),
@@ -731,27 +710,25 @@
   quiche_send_info send_info;
 };
 
-static ssize_t read_pkt_to_send(void *userp,
-                                unsigned char *buf, size_t buflen,
-                                CURLcode *err)
+static CURLcode read_pkt_to_send(void *userp,
+                                 unsigned char *buf, size_t buflen,
+                                 size_t *pnread)
 {
   struct read_ctx *x = userp;
   struct cf_quiche_ctx *ctx = x->cf->ctx;
-  ssize_t nwritten;
+  ssize_t n;
 
-  nwritten = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info);
-  if(nwritten == QUICHE_ERR_DONE) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
+  *pnread = 0;
+  n = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info);
+  if(n == QUICHE_ERR_DONE)
+    return CURLE_AGAIN;
 
-  if(nwritten < 0) {
-    failf(x->data, "quiche_conn_send returned %zd", nwritten);
-    *err = CURLE_SEND_ERROR;
-    return -1;
+  if(n < 0) {
+    failf(x->data, "quiche_conn_send returned %zd", n);
+    return CURLE_SEND_ERROR;
   }
-  *err = CURLE_OK;
-  return nwritten;
+  *pnread = (size_t)n;
+  return CURLE_OK;
 }
 
 /*
@@ -762,7 +739,7 @@
                                 struct Curl_easy *data)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
-  ssize_t nread;
+  size_t nread;
   CURLcode result;
   curl_int64_t expiry_ns;
   curl_int64_t timeout_ns;
@@ -800,9 +777,9 @@
   gsolen = quiche_conn_max_send_udp_payload_size(ctx->qconn);
   for(;;) {
     /* add the next packet to send, if any, to our buffer */
-    nread = Curl_bufq_sipn(&ctx->q.sendbuf, 0,
-                           read_pkt_to_send, &readx, &result);
-    if(nread < 0) {
+    result = Curl_bufq_sipn(&ctx->q.sendbuf, 0,
+                            read_pkt_to_send, &readx, &nread);
+    if(result) {
       if(result != CURLE_AGAIN)
         return result;
       /* Nothing more to add, flush and leave */
@@ -818,7 +795,7 @@
     }
 
     ++pkt_count;
-    if((size_t)nread < gsolen || pkt_count >= MAX_PKT_BURST) {
+    if(nread < gsolen || pkt_count >= MAX_PKT_BURST) {
       result = vquic_send(cf, data, &ctx->q, gsolen);
       if(result) {
         if(result == CURLE_AGAIN) {
@@ -840,123 +817,105 @@
   return result;
 }
 
-static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  CURLcode *err)
+static CURLcode recv_closed_stream(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   size_t *pnread)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
+  CURLcode result = CURLE_OK;
 
   DEBUGASSERT(stream);
+  *pnread = 0;
   if(stream->reset) {
     failf(data,
           "HTTP/3 stream %" FMT_PRIu64 " reset by server", stream->id);
-    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+    result = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, was reset -> %d",
-                stream->id, *err);
+                stream->id, result);
   }
   else if(!stream->resp_got_header) {
     failf(data,
           "HTTP/3 stream %" FMT_PRIu64 " was closed cleanly, but before "
           "getting all response header fields, treated as error",
           stream->id);
-    /* *err = CURLE_PARTIAL_FILE; */
-    *err = CURLE_HTTP3;
-    CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, closed incomplete"
-                " -> %d", stream->id, *err);
+    result = CURLE_HTTP3;
   }
-  else {
-    *err = CURLE_OK;
-    nread = 0;
-  }
-  return nread;
+  return result;
 }
 
-static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              char *buf, size_t len, CURLcode *err)
+static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                               char *buf, size_t len, size_t *pnread)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
-  CURLcode result;
+  CURLcode result = CURLE_OK;
 
+  *pnread = 0;
   vquic_ctx_update_time(&ctx->q);
 
-  if(!stream) {
-    *err = CURLE_RECV_ERROR;
-    return -1;
-  }
+  if(!stream)
+    return CURLE_RECV_ERROR;
+
 
   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, err);
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
-                "-> %zd, %d", stream->id, len, nread, *err);
-    if(nread < 0)
+                "-> %d, %zu", stream->id, len, result, *pnread);
+    if(result)
       goto out;
   }
 
   if(cf_process_ingress(cf, data)) {
     CURL_TRC_CF(data, cf, "cf_recv, error on ingress");
-    *err = CURLE_RECV_ERROR;
-    nread = -1;
+    result = CURLE_RECV_ERROR;
     goto out;
   }
 
   /* recvbuf had nothing before, maybe after progressing ingress? */
-  if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, err);
+  if(!*pnread && !Curl_bufq_is_empty(&stream->recvbuf)) {
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
-                "-> %zd, %d", stream->id, len, nread, *err);
-    if(nread < 0)
+                "-> %d, %zu", stream->id, len, result, *pnread);
+    if(result)
       goto out;
   }
 
-  if(nread > 0) {
+  if(*pnread) {
     if(stream->closed)
-      h3_drain_stream(cf, data);
+      Curl_multi_mark_dirty(data);
   }
   else {
-    if(stream->closed) {
-      nread = recv_closed_stream(cf, data, err);
-      goto out;
-    }
+    if(stream->closed)
+      result = recv_closed_stream(cf, data, pnread);
     else if(quiche_conn_is_draining(ctx->qconn)) {
       failf(data, "QUIC connection is draining");
-      *err = CURLE_HTTP3;
-      nread = -1;
-      goto out;
+      result = CURLE_HTTP3;
     }
-    *err = CURLE_AGAIN;
-    nread = -1;
+    else
+      result = CURLE_AGAIN;
   }
 
 out:
-  result = cf_flush_egress(cf, data);
-  if(result) {
-    CURL_TRC_CF(data, cf, "cf_recv, flush egress failed");
-    *err = result;
-    nread = -1;
-  }
-  if(nread > 0)
-    ctx->data_recvd += nread;
+  result = Curl_1st_err(result, cf_flush_egress(cf, data));
+  if(*pnread > 0)
+    ctx->data_recvd += *pnread;
   CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] cf_recv(total=%"
-              FMT_OFF_T ") -> %zd, %d",
-              stream->id, ctx->data_recvd, nread, *err);
-  return nread;
+              FMT_OFF_T ") -> %d, %zu",
+              stream->id, ctx->data_recvd, result, *pnread);
+  return result;
 }
 
-static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf,
-                                   struct Curl_easy *data,
-                                   struct h3_stream_ctx *stream,
-                                   const void *buf, size_t len, bool eos,
-                                   CURLcode *err)
+static CURLcode cf_quiche_send_body(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    struct h3_stream_ctx *stream,
+                                    const void *buf, size_t len, bool eos,
+                                    size_t *pnwritten)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   ssize_t nwritten;
 
+  *pnwritten = 0;
   nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
                                  (uint8_t *)CURL_UNCONST(buf), len, eos);
   if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
@@ -967,26 +926,22 @@
                   "-> window exhausted", stream->id, len);
       stream->quic_flow_blocked = TRUE;
     }
-    *err = CURLE_AGAIN;
-    return -1;
+    return CURLE_AGAIN;
   }
   else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
                 "-> invalid stream state", stream->id, len);
-    *err = CURLE_HTTP3;
-    return -1;
+    return CURLE_HTTP3;
   }
   else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
                 "-> exceeds size", stream->id, len);
-    *err = CURLE_SEND_ERROR;
-    return -1;
+    return CURLE_SEND_ERROR;
   }
   else if(nwritten < 0) {
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
                 "-> quiche err %zd", stream->id, len, nwritten);
-    *err = CURLE_SEND_ERROR;
-    return -1;
+    return CURLE_SEND_ERROR;
   }
   else {
     if(eos && (len == (size_t)nwritten))
@@ -994,8 +949,8 @@
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send body(len=%zu, "
                 "eos=%d) -> %zd",
                 stream->id, len, stream->send_closed, nwritten);
-    *err = CURLE_OK;
-    return nwritten;
+    *pnwritten = (size_t)nwritten;
+    return CURLE_OK;
   }
 }
 
@@ -1003,10 +958,10 @@
    field list. */
 #define AUTHORITY_DST_IDX 3
 
-static ssize_t h3_open_stream(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              const char *buf, size_t len, bool eos,
-                              CURLcode *err)
+static CURLcode h3_open_stream(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               const char *buf, size_t blen, bool eos,
+                               size_t *pnwritten)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
@@ -1014,13 +969,14 @@
   curl_int64_t stream3_id;
   struct dynhds h2_headers;
   quiche_h3_header *nva = NULL;
+  CURLcode result = CURLE_OK;
   ssize_t nwritten;
 
+  *pnwritten = 0;
   if(!stream) {
-    *err = h3_data_setup(cf, data);
-    if(*err) {
-      return -1;
-    }
+    result = h3_data_setup(cf, data);
+    if(result)
+      return result;
     stream = H3_STREAM_CTX(ctx, data);
     DEBUGASSERT(stream);
   }
@@ -1028,7 +984,7 @@
   Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
 
   DEBUGASSERT(stream);
-  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
+  nwritten = Curl_h1_req_parse_read(&stream->h1, buf, blen, NULL, 0, &result);
   if(nwritten < 0)
     goto out;
   if(!stream->h1.done) {
@@ -1037,19 +993,17 @@
   }
   DEBUGASSERT(stream->h1.req);
 
-  *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
-  if(*err) {
-    nwritten = -1;
+  result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
+  if(result)
     goto out;
-  }
+
   /* no longer needed */
   Curl_h1_req_parse_free(&stream->h1);
 
   nheader = Curl_dynhds_count(&h2_headers);
   nva = malloc(sizeof(quiche_h3_header) * nheader);
   if(!nva) {
-    *err = CURLE_OUT_OF_MEMORY;
-    nwritten = -1;
+    result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
 
@@ -1061,7 +1015,11 @@
     nva[i].value_len = e->valuelen;
   }
 
-  if(eos && ((size_t)nwritten == len))
+  *pnwritten = (size_t)nwritten;
+  buf += *pnwritten;
+  blen -= *pnwritten;
+
+  if(eos && !blen)
     stream->send_closed = TRUE;
 
   stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader,
@@ -1072,21 +1030,18 @@
        * exhausted. Which happens frequently and intermittent. */
       CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] blocked", stream->id);
       stream->quic_flow_blocked = TRUE;
-      *err = CURLE_AGAIN;
-      nwritten = -1;
+      result = CURLE_AGAIN;
       goto out;
     }
     else {
       CURL_TRC_CF(data, cf, "send_request(%s) -> %" FMT_PRIu64,
                   data->state.url, stream3_id);
     }
-    *err = CURLE_SEND_ERROR;
-    nwritten = -1;
+    result = CURLE_SEND_ERROR;
     goto out;
   }
 
   DEBUGASSERT(!stream->opened);
-  *err = CURLE_OK;
   stream->id = stream3_id;
   stream->opened = TRUE;
   stream->closed = FALSE;
@@ -1102,48 +1057,43 @@
     }
   }
 
-  if(nwritten > 0 && ((size_t)nwritten < len)) {
-    /* after the headers, there was request BODY data */
-    size_t hds_len = (size_t)nwritten;
-    ssize_t bwritten;
+  if(blen) {  /* after the headers, there was request BODY data */
+    size_t bwritten;
+    CURLcode r2 = CURLE_OK;
 
-    bwritten = cf_quiche_send_body(cf, data, stream,
-                                   buf + hds_len, len - hds_len, eos, err);
-    if((bwritten < 0) && (CURLE_AGAIN != *err)) {
-      /* real error, fail */
-      nwritten = -1;
+    r2 = cf_quiche_send_body(cf, data, stream, buf, blen, eos, &bwritten);
+    if(r2 && (CURLE_AGAIN != r2)) {  /* real error, fail */
+      result = r2;
     }
     else if(bwritten > 0) {
-      nwritten += bwritten;
+      *pnwritten += (size_t)bwritten;
     }
   }
 
 out:
   free(nva);
   Curl_dynhds_free(&h2_headers);
-  return nwritten;
+  return result;
 }
 
-static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              const void *buf, size_t len, bool eos,
-                              CURLcode *err)
+static CURLcode cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                               const void *buf, size_t len, bool eos,
+                               size_t *pnwritten)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
   CURLcode result;
-  ssize_t nwritten;
 
+  *pnwritten = 0;
   vquic_ctx_update_time(&ctx->q);
 
-  *err = cf_process_ingress(cf, data);
-  if(*err) {
-    nwritten = -1;
+  result = cf_process_ingress(cf, data);
+  if(result)
     goto out;
-  }
 
   if(!stream || !stream->opened) {
-    nwritten = h3_open_stream(cf, data, buf, len, eos, err);
-    if(nwritten < 0)
+    result = h3_open_stream(cf, data, buf, len, eos, pnwritten);
+    if(result)
       goto out;
     stream = H3_STREAM_CTX(ctx, data);
   }
@@ -1159,29 +1109,26 @@
        * it would see the response and stop/discard sending on its own- */
       CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] discarding data"
                   "on closed stream with response", stream->id);
-      *err = CURLE_OK;
-      nwritten = (ssize_t)len;
+      result = CURLE_OK;
+      *pnwritten = len;
       goto out;
     }
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
                 "-> stream closed", stream->id, len);
-    *err = CURLE_HTTP3;
-    nwritten = -1;
+    result = CURLE_HTTP3;
     goto out;
   }
   else {
-    nwritten = cf_quiche_send_body(cf, data, stream, buf, len, eos, err);
+    result = cf_quiche_send_body(cf, data, stream, buf, len, eos, pnwritten);
   }
 
 out:
-  result = cf_flush_egress(cf, data);
-  if(result) {
-    *err = result;
-    nwritten = -1;
-  }
-  CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
-              stream ? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
-  return nwritten;
+  result = Curl_1st_err(result, cf_flush_egress(cf, data));
+
+  CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %d, %zu",
+              stream ? stream->id : (curl_uint64_t)~0, len,
+              result, *pnwritten);
+  return result;
 }
 
 static bool stream_is_writeable(struct Curl_cfilter *cf,
@@ -1240,9 +1187,9 @@
 {
   /* There seems to exist no API in quiche to shrink/enlarge the streams
    * windows. As we do in HTTP/2. */
+  (void)cf;
   if(!pause) {
-    h3_drain_stream(cf, data);
-    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+    Curl_multi_mark_dirty(data);
   }
   return CURLE_OK;
 }
@@ -1269,13 +1216,13 @@
     struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
     if(stream && !stream->send_closed) {
       unsigned char body[1];
-      ssize_t sent;
+      size_t sent;
 
       stream->send_closed = TRUE;
       body[0] = 'X';
-      sent = cf_quiche_send(cf, data, body, 0, TRUE, &result);
-      CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] DONE_SEND -> %zd, %d",
-                  stream->id, sent, result);
+      result = cf_quiche_send(cf, data, body, 0, TRUE, &sent);
+      CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] DONE_SEND -> %d, %zu",
+                  stream->id, result, sent);
     }
     break;
   }
@@ -1569,7 +1516,7 @@
   switch(query) {
   case CF_QUERY_MAX_CONCURRENT: {
     curl_uint64_t max_streams = CONN_ATTACHED(cf->conn);
-    if(!ctx->goaway) {
+    if(!ctx->goaway && ctx->qconn) {
       max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
     }
     *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
@@ -1601,6 +1548,14 @@
   case CF_QUERY_HTTP_VERSION:
     *pres1 = 30;
     return CURLE_OK;
+  case CF_QUERY_SSL_INFO:
+  case CF_QUERY_SSL_CTX_INFO: {
+    struct curl_tlssessioninfo *info = pres2;
+    if(Curl_vquic_tls_get_ssl_info(&ctx->tls,
+                                   (query == CF_QUERY_SSL_INFO), info))
+      return CURLE_OK;
+    break;
+  }
   default:
     break;
   }
@@ -1654,7 +1609,6 @@
   cf_quiche_connect,
   cf_quiche_close,
   cf_quiche_shutdown,
-  Curl_cf_def_get_host,
   cf_quiche_adjust_pollset,
   cf_quiche_data_pending,
   cf_quiche_send,
@@ -1707,20 +1661,4 @@
   return result;
 }
 
-bool Curl_conn_is_quiche(const struct Curl_easy *data,
-                         const struct connectdata *conn,
-                         int sockindex)
-{
-  struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
-
-  (void)data;
-  for(; cf; cf = cf->next) {
-    if(cf->cft == &Curl_cft_http3)
-      return TRUE;
-    if(cf->cft->flags & CF_TYPE_IP_CONNECT)
-      return FALSE;
-  }
-  return FALSE;
-}
-
 #endif
diff --git a/Utilities/cmcurl/lib/vquic/curl_quiche.h b/Utilities/cmcurl/lib/vquic/curl_quiche.h
index 9832687..b2c7672 100644
--- a/Utilities/cmcurl/lib/vquic/curl_quiche.h
+++ b/Utilities/cmcurl/lib/vquic/curl_quiche.h
@@ -41,10 +41,6 @@
                                struct connectdata *conn,
                                const struct Curl_addrinfo *ai);
 
-bool Curl_conn_is_quiche(const struct Curl_easy *data,
-                         const struct connectdata *conn,
-                         int sockindex);
-
 #endif
 
 #endif /* HEADER_CURL_VQUIC_CURL_QUICHE_H */
diff --git a/Utilities/cmcurl/lib/vquic/vquic-tls.c b/Utilities/cmcurl/lib/vquic/vquic-tls.c
index 2a5be13..8a53c83 100644
--- a/Utilities/cmcurl/lib/vquic/vquic-tls.c
+++ b/Utilities/cmcurl/lib/vquic/vquic-tls.c
@@ -197,4 +197,46 @@
 }
 
 
+bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx,
+                                 bool give_ssl_ctx,
+                                 struct curl_tlssessioninfo *info)
+{
+#ifdef USE_OPENSSL
+  info->backend = CURLSSLBACKEND_OPENSSL;
+  info->internals = give_ssl_ctx ?
+                    (void *)ctx->ossl.ssl_ctx : (void *)ctx->ossl.ssl;
+  return TRUE;
+#elif defined(USE_GNUTLS)
+  (void)give_ssl_ctx; /* gnutls always returns its session */
+  info->backend = CURLSSLBACKEND_OPENSSL;
+  info->internals = ctx->gtls.session;
+  return TRUE;
+#elif defined(USE_WOLFSSL)
+  info->backend = CURLSSLBACKEND_WOLFSSL;
+  info->internals = give_ssl_ctx ?
+                    (void *)ctx->wssl.ssl_ctx : (void *)ctx->wssl.ssl;
+  return TRUE;
+#else
+  return FALSE;
+#endif
+}
+
+void Curl_vquic_report_handshake(struct curl_tls_ctx *ctx,
+                                 struct Curl_cfilter *cf,
+                                 struct Curl_easy *data)
+{
+  (void)cf;
+#ifdef USE_OPENSSL
+  (void)cf;
+  Curl_ossl_report_handshake(data, &ctx->ossl);
+#elif defined(USE_GNUTLS)
+  Curl_gtls_report_handshake(data, &ctx->gtls);
+#elif defined(USE_WOLFSSL)
+  Curl_wssl_report_handshake(data, &ctx->wssl);
+#else
+  (void)data;
+  (void)ctx;
+#endif
+}
+
 #endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
diff --git a/Utilities/cmcurl/lib/vquic/vquic-tls.h b/Utilities/cmcurl/lib/vquic/vquic-tls.h
index bf29eec..c694e23 100644
--- a/Utilities/cmcurl/lib/vquic/vquic-tls.h
+++ b/Utilities/cmcurl/lib/vquic/vquic-tls.h
@@ -37,6 +37,7 @@
 
 struct ssl_peer;
 struct Curl_ssl_session;
+struct curl_tlssessioninfo;
 
 struct curl_tls_ctx {
 #ifdef USE_OPENSSL
@@ -106,6 +107,14 @@
                                     struct Curl_easy *data,
                                     struct ssl_peer *peer);
 
+bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx,
+                                 bool give_ssl_ctx,
+                                 struct curl_tlssessioninfo *info);
+
+void Curl_vquic_report_handshake(struct curl_tls_ctx *ctx,
+                                 struct Curl_cfilter *cf,
+                                 struct Curl_easy *data);
+
 #endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
 
 #endif /* HEADER_CURL_VQUIC_TLS_H */
diff --git a/Utilities/cmcurl/lib/vquic/vquic.c b/Utilities/cmcurl/lib/vquic/vquic.c
index b5dc44f..691c0d3 100644
--- a/Utilities/cmcurl/lib/vquic/vquic.c
+++ b/Utilities/cmcurl/lib/vquic/vquic.c
@@ -308,7 +308,7 @@
 }
 
 CURLcode vquic_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                        struct cf_quic_ctx *qctx, size_t gsolen)
+                    struct cf_quic_ctx *qctx, size_t gsolen)
 {
   qctx->gsolen = gsolen;
   return vquic_flush(cf, data, qctx);
@@ -703,9 +703,10 @@
 }
 
 CURLcode Curl_conn_may_http3(struct Curl_easy *data,
-                             const struct connectdata *conn)
+                             const struct connectdata *conn,
+                             unsigned char transport)
 {
-  if(conn->transport == TRNSPRT_UNIX) {
+  if(transport == TRNSPRT_UNIX) {
     /* cannot do QUIC over a Unix domain socket */
     return CURLE_QUIC_CONNECT_ERROR;
   }
@@ -730,10 +731,12 @@
 #else /* USE_HTTP3 */
 
 CURLcode Curl_conn_may_http3(struct Curl_easy *data,
-                             const struct connectdata *conn)
+                             const struct connectdata *conn,
+                             unsigned char transport)
 {
   (void)conn;
   (void)data;
+  (void)transport;
   DEBUGF(infof(data, "QUIC is not supported in this build"));
   return CURLE_NOT_BUILT_IN;
 }
diff --git a/Utilities/cmcurl/lib/vquic/vquic.h b/Utilities/cmcurl/lib/vquic/vquic.h
index dbf63b1..3577a85 100644
--- a/Utilities/cmcurl/lib/vquic/vquic.h
+++ b/Utilities/cmcurl/lib/vquic/vquic.h
@@ -54,6 +54,7 @@
 #endif /* !USE_HTTP3 */
 
 CURLcode Curl_conn_may_http3(struct Curl_easy *data,
-                             const struct connectdata *conn);
+                             const struct connectdata *conn,
+                             unsigned char transport);
 
 #endif /* HEADER_CURL_VQUIC_QUIC_H */
diff --git a/Utilities/cmcurl/lib/vquic/vquic_int.h b/Utilities/cmcurl/lib/vquic/vquic_int.h
index 4641c31..d271368 100644
--- a/Utilities/cmcurl/lib/vquic/vquic_int.h
+++ b/Utilities/cmcurl/lib/vquic/vquic_int.h
@@ -68,7 +68,7 @@
                                  struct cf_quic_ctx *qctx);
 
 CURLcode vquic_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                        struct cf_quic_ctx *qctx, size_t gsolen);
+                    struct cf_quic_ctx *qctx, size_t gsolen);
 
 CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data,
                                struct cf_quic_ctx *qctx, size_t gsolen,
diff --git a/Utilities/cmcurl/lib/vssh/curl_path.c b/Utilities/cmcurl/lib/vssh/curl_path.c
index 117d2e6..474a5ec 100644
--- a/Utilities/cmcurl/lib/vssh/curl_path.c
+++ b/Utilities/cmcurl/lib/vssh/curl_path.c
@@ -84,6 +84,12 @@
         return CURLE_OUT_OF_MEMORY;
       }
     }
+    else {
+      if(curlx_dyn_add(&npath, "/")) {
+        free(working_path);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
   }
 
   if(curlx_dyn_len(&npath)) {
diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c
index 86f1e1a..3bae943 100644
--- a/Utilities/cmcurl/lib/vssh/libssh.c
+++ b/Utilities/cmcurl/lib/vssh/libssh.c
@@ -58,11 +58,9 @@
 #include "../speedcheck.h"
 #include "../getinfo.h"
 #include "../strdup.h"
-#include "../strcase.h"
 #include "../vtls/vtls.h"
 #include "../cfilters.h"
 #include "../connect.h"
-#include "../inet_ntop.h"
 #include "../parsedate.h"          /* for the week day and month names */
 #include "../sockaddr.h"           /* required for Curl_sockaddr_storage */
 #include "../curlx/strparse.h"
@@ -71,9 +69,6 @@
 #include "../curlx/warnless.h"
 #include "curl_path.h"
 
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -130,10 +125,6 @@
                       bool *connected,
                       bool *dophase_done);
 
-static void sftp_quote(struct Curl_easy *data,
-                       struct ssh_conn *sshc,
-                       struct SSHPROTO *sshp);
-static void sftp_quote_stat(struct Curl_easy *data, struct ssh_conn *sshc);
 static int myssh_getsock(struct Curl_easy *data,
                          struct connectdata *conn, curl_socket_t *sock);
 static void myssh_block2waitfor(struct connectdata *conn,
@@ -228,9 +219,9 @@
 }
 
 #ifndef DEBUGBUILD
-#define myssh_state(x,y,z) myssh_set_state(x,y,z)
+#define myssh_to(x,y,z) myssh_set_state(x,y,z)
 #else
-#define myssh_state(x,y,z) myssh_set_state(x,y,z, __LINE__)
+#define myssh_to(x,y,z) myssh_set_state(x,y,z, __LINE__)
 #endif
 
 /*
@@ -371,7 +362,7 @@
 
     infof(data, "SSH MD5 fingerprint: %s", md5buffer);
 
-    if(!strcasecompare(md5buffer, pubkey_md5)) {
+    if(!curl_strequal(md5buffer, pubkey_md5)) {
       failf(data,
             "Denied establishing ssh session: mismatch md5 fingerprint. "
             "Remote %s is not equal to %s", md5buffer, pubkey_md5);
@@ -519,52 +510,302 @@
   return rc;
 }
 
-#define MOVE_TO_ERROR_STATE(_r) do {                      \
-    myssh_state(data, sshc, SSH_SESSION_DISCONNECT);      \
-    sshc->actualcode = _r;                                \
-    rc = SSH_ERROR;                                       \
-  } while(0)
+static int myssh_to_ERROR(struct Curl_easy *data,
+                          struct ssh_conn *sshc,
+                          CURLcode result)
+{
+  myssh_to(data, sshc, SSH_SESSION_DISCONNECT);
+  sshc->actualcode = result;
+  return SSH_ERROR;
+}
 
-#define MOVE_TO_SFTP_CLOSE_STATE() do {                         \
-    myssh_state(data, sshc, SSH_SFTP_CLOSE);                    \
-    sshc->actualcode =                                          \
-      sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session));  \
-    rc = SSH_ERROR;                                             \
-  } while(0)
+static int myssh_to_SFTP_CLOSE(struct Curl_easy *data,
+                               struct ssh_conn *sshc)
+{
+  myssh_to(data, sshc, SSH_SFTP_CLOSE);
+  sshc->actualcode =
+    sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session));
+  return SSH_ERROR;
+}
 
-#define MOVE_TO_PASSWD_AUTH do {                        \
-    if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
-      rc = SSH_OK;                                      \
-      myssh_state(data, sshc, SSH_AUTH_PASS_INIT);      \
-    }                                                   \
-    else {                                              \
-      MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);          \
-    }                                                   \
-  } while(0)
+static int myssh_to_PASSWD_AUTH(struct Curl_easy *data,
+                                struct ssh_conn *sshc)
+{
+  if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
+    myssh_to(data, sshc, SSH_AUTH_PASS_INIT);
+    return SSH_OK;
+  }
+  return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
+}
 
-#define MOVE_TO_KEY_AUTH do {                                   \
-    if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {      \
-      rc = SSH_OK;                                              \
-      myssh_state(data, sshc, SSH_AUTH_KEY_INIT);               \
-    }                                                           \
-    else {                                                      \
-      MOVE_TO_PASSWD_AUTH;                                      \
-    }                                                           \
-  } while(0)
+static int myssh_to_KEY_AUTH(struct Curl_easy *data,
+                             struct ssh_conn *sshc)
+{
+  if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
+    myssh_to(data, sshc, SSH_AUTH_KEY_INIT);
+    return SSH_OK;
+  }
+  return myssh_to_PASSWD_AUTH(data, sshc);
+}
 
-#define MOVE_TO_GSSAPI_AUTH do {                                \
-    if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {       \
-      rc = SSH_OK;                                              \
-      myssh_state(data, sshc, SSH_AUTH_GSSAPI);                 \
-    }                                                           \
-    else {                                                      \
-      MOVE_TO_KEY_AUTH;                                         \
-    }                                                           \
-  } while(0)
+static int myssh_to_GSSAPI_AUTH(struct Curl_easy *data,
+                                struct ssh_conn *sshc)
+{
+  if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
+    myssh_to(data, sshc, SSH_AUTH_GSSAPI);
+    return SSH_OK;
+  }
+  return myssh_to_KEY_AUTH(data, sshc);
+}
 
-static
-int myssh_auth_interactive(struct connectdata *conn,
-                           struct ssh_conn *sshc)
+static int myssh_in_SFTP_READDIR_INIT(struct Curl_easy *data,
+                                      struct ssh_conn *sshc,
+                                      struct SSHPROTO *sshp)
+{
+  Curl_pgrsSetDownloadSize(data, -1);
+  if(data->req.no_body) {
+    myssh_to(data, sshc, SSH_STOP);
+    return SSH_NO_ERROR;
+  }
+
+  /*
+   * This is a directory that we are trying to get, so produce a directory
+   * listing
+   */
+  sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
+                                sshp->path);
+  if(!sshc->sftp_dir) {
+    failf(data, "Could not open directory for reading: %s",
+          ssh_get_error(sshc->ssh_session));
+    return myssh_to_SFTP_CLOSE(data, sshc);
+  }
+  myssh_to(data, sshc, SSH_SFTP_READDIR);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_READDIR(struct Curl_easy *data,
+                                 struct ssh_conn *sshc,
+                                 struct SSHPROTO *sshp)
+{
+  CURLcode result = CURLE_OK;
+
+  curlx_dyn_reset(&sshc->readdir_buf);
+  if(sshc->readdir_attrs)
+    sftp_attributes_free(sshc->readdir_attrs);
+
+  sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
+  if(sshc->readdir_attrs) {
+    sshc->readdir_filename = sshc->readdir_attrs->name;
+    sshc->readdir_longentry = sshc->readdir_attrs->longname;
+    sshc->readdir_len = strlen(sshc->readdir_filename);
+
+    if(data->set.list_only) {
+      char *tmpLine;
+
+      tmpLine = aprintf("%s\n", sshc->readdir_filename);
+      if(!tmpLine) {
+        myssh_to(data, sshc, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        return SSH_ERROR;
+      }
+      result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                 tmpLine, sshc->readdir_len + 1);
+      free(tmpLine);
+
+      if(result) {
+        myssh_to(data, sshc, SSH_STOP);
+        return SSH_NO_ERROR;
+      }
+
+    }
+    else {
+      if(curlx_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        myssh_to(data, sshc, SSH_STOP);
+        return SSH_ERROR;
+      }
+
+      if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
+         ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
+          SSH_S_IFLNK)) {
+        sshc->readdir_linkPath = aprintf("%s%s", sshp->path,
+                                         sshc->readdir_filename);
+
+        if(!sshc->readdir_linkPath) {
+          myssh_to(data, sshc, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          return SSH_ERROR;
+        }
+
+        myssh_to(data, sshc, SSH_SFTP_READDIR_LINK);
+        return SSH_NO_ERROR;
+      }
+      myssh_to(data, sshc, SSH_SFTP_READDIR_BOTTOM);
+      return SSH_NO_ERROR;
+    }
+  }
+  else if(sftp_dir_eof(sshc->sftp_dir)) {
+    myssh_to(data, sshc, SSH_SFTP_READDIR_DONE);
+  }
+  else {
+    failf(data, "Could not open remote directory for reading: %s",
+          ssh_get_error(sshc->ssh_session));
+    return myssh_to_SFTP_CLOSE(data, sshc);
+  }
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_READDIR_LINK(struct Curl_easy *data,
+                                      struct ssh_conn *sshc)
+{
+  if(sshc->readdir_link_attrs)
+    sftp_attributes_free(sshc->readdir_link_attrs);
+
+  sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
+                                        sshc->readdir_linkPath);
+  if(!sshc->readdir_link_attrs) {
+    failf(data, "Could not read symlink for reading: %s",
+          ssh_get_error(sshc->ssh_session));
+    return myssh_to_SFTP_CLOSE(data, sshc);
+  }
+
+  if(!sshc->readdir_link_attrs->name) {
+    sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
+                                      sshc->readdir_linkPath);
+    if(!sshc->readdir_tmp)
+      sshc->readdir_len = 0;
+    else
+      sshc->readdir_len = strlen(sshc->readdir_tmp);
+    sshc->readdir_longentry = NULL;
+    sshc->readdir_filename = sshc->readdir_tmp;
+  }
+  else {
+    sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
+    sshc->readdir_filename = sshc->readdir_link_attrs->name;
+    sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
+  }
+
+  Curl_safefree(sshc->readdir_linkPath);
+
+  if(curlx_dyn_addf(&sshc->readdir_buf, " -> %s",
+                    sshc->readdir_filename)) {
+    /* Not using:
+     * return myssh_to_SFTP_CLOSE(data, sshc);
+     *
+     * as that assumes an sftp related error while
+     * assigning sshc->actualcode whereas the current
+     * error is curlx_dyn_addf() related.
+     */
+    myssh_to(data, sshc, SSH_SFTP_CLOSE);
+    sshc->actualcode = CURLE_OUT_OF_MEMORY;
+    return SSH_ERROR;
+  }
+
+  sftp_attributes_free(sshc->readdir_link_attrs);
+  sshc->readdir_link_attrs = NULL;
+  sshc->readdir_filename = NULL;
+  sshc->readdir_longentry = NULL;
+
+  myssh_to(data, sshc, SSH_SFTP_READDIR_BOTTOM);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_READDIR_BOTTOM(struct Curl_easy *data,
+                                        struct ssh_conn *sshc)
+{
+  CURLcode result;
+
+  if(curlx_dyn_addn(&sshc->readdir_buf, "\n", 1))
+    result = CURLE_OUT_OF_MEMORY;
+  else
+    result = Curl_client_write(data, CLIENTWRITE_BODY,
+                               curlx_dyn_ptr(&sshc->readdir_buf),
+                               curlx_dyn_len(&sshc->readdir_buf));
+
+  ssh_string_free_char(sshc->readdir_tmp);
+  sshc->readdir_tmp = NULL;
+
+  if(result)
+    myssh_to(data, sshc, SSH_STOP);
+  else
+    myssh_to(data, sshc, SSH_SFTP_READDIR);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_READDIR_DONE(struct Curl_easy *data,
+                                      struct ssh_conn *sshc)
+{
+  sftp_closedir(sshc->sftp_dir);
+  sshc->sftp_dir = NULL;
+
+  /* no data to transfer */
+  Curl_xfer_setup_nop(data);
+  myssh_to(data, sshc, SSH_STOP);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data,
+                                       struct ssh_conn *sshc)
+{
+  sftp_statvfs_t statvfs;
+
+  statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
+  if(!statvfs && !sshc->acceptfail) {
+    Curl_safefree(sshc->quote_path1);
+    failf(data, "statvfs command failed: %s",
+          ssh_get_error(sshc->ssh_session));
+    myssh_to(data, sshc, SSH_SFTP_CLOSE);
+    sshc->nextstate = SSH_NO_STATE;
+    sshc->actualcode = CURLE_QUOTE_ERROR;
+    return SSH_OK;
+  }
+  else if(statvfs) {
+    #ifdef _MSC_VER
+    #define CURL_LIBSSH_VFS_SIZE_MASK "I64u"
+    #else
+    #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64
+    #endif
+    CURLcode result;
+    char *tmp = aprintf("statvfs:\n"
+                        "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
+                        "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n",
+                        statvfs->f_bsize, statvfs->f_frsize,
+                        statvfs->f_blocks, statvfs->f_bfree,
+                        statvfs->f_bavail, statvfs->f_files,
+                        statvfs->f_ffree, statvfs->f_favail,
+                        statvfs->f_fsid, statvfs->f_flag,
+                        statvfs->f_namemax);
+    sftp_statvfs_free(statvfs);
+
+    if(!tmp) {
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      return SSH_OK;
+    }
+
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+    free(tmp);
+    if(result) {
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+    }
+  }
+  myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
+  return SSH_OK;
+}
+
+static int myssh_auth_interactive(struct connectdata *conn,
+                                  struct ssh_conn *sshc)
 {
   int rc;
   int nprompts;
@@ -642,11 +883,11 @@
      non-blocking */
   ssh_set_blocking(sshc->ssh_session, 0);
 
-  myssh_state(data, sshc, SSH_S_STARTUP);
+  myssh_to(data, sshc, SSH_S_STARTUP);
 }
 
-static int myssh_state_startup(struct Curl_easy *data,
-                               struct ssh_conn *sshc)
+static int myssh_in_S_STARTUP(struct Curl_easy *data,
+                              struct ssh_conn *sshc)
 {
   struct connectdata *conn = data->conn;
   int rc = ssh_connect(sshc->ssh_session);
@@ -657,16 +898,16 @@
   }
   else if(rc != SSH_OK) {
     failf(data, "Failure establishing ssh session");
-    MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
+    rc = myssh_to_ERROR(data, sshc, CURLE_FAILED_INIT);
   }
   else
-    myssh_state(data, sshc, SSH_HOSTKEY);
+    myssh_to(data, sshc, SSH_HOSTKEY);
 
   return rc;
 }
 
-static int myssh_state_authlist(struct Curl_easy *data,
-                                struct ssh_conn *sshc)
+static int myssh_in_AUTHLIST(struct Curl_easy *data,
+                             struct ssh_conn *sshc)
 {
   int rc;
   sshc->authed = FALSE;
@@ -678,11 +919,11 @@
   if(rc == SSH_AUTH_SUCCESS) {
     sshc->authed = TRUE;
     infof(data, "Authenticated with none");
-    myssh_state(data, sshc, SSH_AUTH_DONE);
+    myssh_to(data, sshc, SSH_AUTH_DONE);
     return rc;
   }
   else if(rc == SSH_AUTH_ERROR) {
-    MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+    rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
     return rc;
   }
 
@@ -699,31 +940,31 @@
           sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ?
           "password": "");
   if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
-    myssh_state(data, sshc, SSH_AUTH_PKEY_INIT);
+    myssh_to(data, sshc, SSH_AUTH_PKEY_INIT);
     infof(data, "Authentication using SSH public key file");
   }
   else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
-    myssh_state(data, sshc, SSH_AUTH_GSSAPI);
+    myssh_to(data, sshc, SSH_AUTH_GSSAPI);
   }
   else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) {
-    myssh_state(data, sshc, SSH_AUTH_KEY_INIT);
+    myssh_to(data, sshc, SSH_AUTH_KEY_INIT);
   }
   else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) {
-    myssh_state(data, sshc, SSH_AUTH_PASS_INIT);
+    myssh_to(data, sshc, SSH_AUTH_PASS_INIT);
   }
   else {                  /* unsupported authentication method */
-    MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+    rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
   }
   return rc;
 }
 
-static int myssh_state_auth_pkey_init(struct Curl_easy *data,
-                                      struct ssh_conn *sshc)
+static int myssh_in_AUTH_PKEY_INIT(struct Curl_easy *data,
+                                   struct ssh_conn *sshc)
 {
   int rc;
   if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
-    MOVE_TO_GSSAPI_AUTH;
-    return 0;
+    rc = myssh_to_GSSAPI_AUTH(data, sshc);
+    return rc;
   }
 
   /* Two choices, (1) private key was given on CMD,
@@ -736,7 +977,7 @@
         return SSH_AGAIN;
 
       if(rc != SSH_OK) {
-        MOVE_TO_GSSAPI_AUTH;
+        rc = myssh_to_GSSAPI_AUTH(data, sshc);
         return rc;
       }
     }
@@ -748,11 +989,11 @@
     if(rc != SSH_OK) {
       failf(data, "Could not load private key file %s",
             data->set.str[STRING_SSH_PRIVATE_KEY]);
-      MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+      rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
       return rc;
     }
 
-    myssh_state(data, sshc, SSH_AUTH_PKEY);
+    myssh_to(data, sshc, SSH_AUTH_PKEY);
   }
   else {
     rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL,
@@ -764,18 +1005,131 @@
       rc = SSH_OK;
       sshc->authed = TRUE;
       infof(data, "Completed public key authentication");
-      myssh_state(data, sshc, SSH_AUTH_DONE);
+      myssh_to(data, sshc, SSH_AUTH_DONE);
       return rc;
     }
 
-    MOVE_TO_GSSAPI_AUTH;
+    rc = myssh_to_GSSAPI_AUTH(data, sshc);
   }
   return rc;
 }
 
-static int myssh_state_upload_init(struct Curl_easy *data,
-                                   struct ssh_conn *sshc,
-                                   struct SSHPROTO *sshp)
+static int myssh_in_AUTH_PKEY(struct Curl_easy *data,
+                              struct ssh_conn *sshc)
+{
+  int rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
+  if(rc == SSH_AUTH_AGAIN)
+    return SSH_AGAIN;
+  else if(rc == SSH_AUTH_SUCCESS) {
+    sshc->authed = TRUE;
+    infof(data, "Completed public key authentication");
+    myssh_to(data, sshc, SSH_AUTH_DONE);
+    return SSH_OK;
+  }
+  else {
+    infof(data, "Failed public key authentication (rc: %d)", rc);
+    return myssh_to_GSSAPI_AUTH(data, sshc);
+  }
+}
+
+static int myssh_in_AUTH_GSSAPI(struct Curl_easy *data,
+                                struct ssh_conn *sshc)
+{
+  int rc;
+  if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI))
+    return myssh_to_KEY_AUTH(data, sshc);
+
+  rc = ssh_userauth_gssapi(sshc->ssh_session);
+  if(rc == SSH_AUTH_AGAIN)
+    return SSH_AGAIN;
+
+  if(rc == SSH_AUTH_SUCCESS) {
+    sshc->authed = TRUE;
+    infof(data, "Completed gssapi authentication");
+    myssh_to(data, sshc, SSH_AUTH_DONE);
+    return SSH_OK;
+  }
+
+  return myssh_to_KEY_AUTH(data, sshc);
+}
+
+static int myssh_in_AUTH_KEY_INIT(struct Curl_easy *data,
+                                  struct ssh_conn *sshc)
+{
+  if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
+    myssh_to(data, sshc, SSH_AUTH_KEY);
+    return SSH_NO_ERROR;
+  }
+  return myssh_to_PASSWD_AUTH(data, sshc);
+}
+
+static int myssh_in_AUTH_KEY(struct Curl_easy *data,
+                             struct ssh_conn *sshc)
+{
+  /* keyboard-interactive authentication */
+  int rc = myssh_auth_interactive(data->conn, sshc);
+  if(rc == SSH_AGAIN)
+    return rc;
+  else if(rc == SSH_OK) {
+    sshc->authed = TRUE;
+    infof(data, "completed keyboard interactive authentication");
+    myssh_to(data, sshc, SSH_AUTH_DONE);
+    return SSH_NO_ERROR;
+  }
+  else
+    return myssh_to_PASSWD_AUTH(data, sshc);
+}
+
+static int myssh_in_AUTH_PASS_INIT(struct Curl_easy *data,
+                                   struct ssh_conn *sshc)
+{
+  if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD))
+    return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
+  myssh_to(data, sshc, SSH_AUTH_PASS);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_AUTH_PASS(struct Curl_easy *data,
+                              struct ssh_conn *sshc)
+{
+  int rc = ssh_userauth_password(sshc->ssh_session, NULL, data->conn->passwd);
+  if(rc == SSH_AUTH_AGAIN)
+    return SSH_AGAIN;
+  else if(rc == SSH_AUTH_SUCCESS) {
+    sshc->authed = TRUE;
+    infof(data, "Completed password authentication");
+    myssh_to(data, sshc, SSH_AUTH_DONE);
+    return SSH_NO_ERROR;
+  }
+  return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
+}
+
+static int myssh_in_AUTH_DONE(struct Curl_easy *data,
+                              struct ssh_conn *sshc)
+{
+  if(!sshc->authed) {
+    failf(data, "Authentication failure");
+    return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED);
+  }
+
+  /* At this point we have an authenticated ssh session. */
+  infof(data, "Authentication complete");
+  Curl_pgrsTime(data, TIMER_APPCONNECT);      /* SSH is connected */
+  data->conn->sockfd = data->conn->sock[FIRSTSOCKET];
+  data->conn->writesockfd = CURL_SOCKET_BAD;
+
+  if(data->conn->handler->protocol == CURLPROTO_SFTP) {
+    myssh_to(data, sshc, SSH_SFTP_INIT);
+    return SSH_NO_ERROR;
+  }
+  infof(data, "SSH CONNECT phase done");
+  myssh_to(data, sshc, SSH_STOP);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_UPLOAD_INIT(struct Curl_easy *data,
+                                struct ssh_conn *sshc,
+                                struct SSHPROTO *sshp)
 {
   int flags;
   int rc = 0;
@@ -789,7 +1143,7 @@
         curl_off_t size = attrs->size;
         if(size < 0) {
           failf(data, "Bad file size (%" FMT_OFF_T ")", size);
-          MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+          rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
           return rc;
         }
         data->state.resume_from = attrs->size;
@@ -827,11 +1181,11 @@
       /* try to create the path remotely */
       rc = 0;
       sshc->secondCreateDirs = 1;
-      myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_INIT);
+      myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS_INIT);
       return rc;
     }
     else {
-      MOVE_TO_SFTP_CLOSE_STATE();
+      rc = myssh_to_SFTP_CLOSE(data, sshc);
       return rc;
     }
   }
@@ -853,7 +1207,7 @@
 
       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
         failf(data, "Could not seek stream");
-        MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
+        rc = myssh_to_ERROR(data, sshc, CURLE_FTP_COULDNT_USE_REST);
         return rc;
       }
       /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
@@ -873,7 +1227,7 @@
           /* this checks for greater-than only to make sure that the
              CURL_READFUNC_ABORT return code still aborts */
           failf(data, "Failed to read data");
-          MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
+          rc = myssh_to_ERROR(data, sshc, CURLE_FTP_COULDNT_USE_REST);
           return rc;
         }
       } while(passed < data->state.resume_from);
@@ -888,7 +1242,7 @@
 
     rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
     if(rc) {
-      MOVE_TO_SFTP_CLOSE_STATE();
+      rc = myssh_to_SFTP_CLOSE(data, sshc);
       return rc;
     }
   }
@@ -906,24 +1260,39 @@
      figure out a "real" bitmask */
   sshc->orig_waitfor = data->req.keepon;
 
-  /* we want to use the _sending_ function even when the socket turns
-     out readable as the underlying libssh sftp send function will deal
-     with both accordingly */
-  data->state.select_bits = CURL_CSELECT_OUT;
-
   /* since we do not really wait for anything at this point, we want the
-     state machine to move on as soon as possible so we set a very short
-     timeout here */
-  Curl_expire(data, 0, EXPIRE_RUN_NOW);
+     state machine to move on as soon as possible so we mark this as dirty */
+  Curl_multi_mark_dirty(data);
 #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
   sshc->sftp_send_state = 0;
 #endif
-  myssh_state(data, sshc, SSH_STOP);
+  myssh_to(data, sshc, SSH_STOP);
   return rc;
 }
 
-static int myssh_state_sftp_download_stat(struct Curl_easy *data,
-                                          struct ssh_conn *sshc)
+static int myssh_in_SFTP_DOWNLOAD_INIT(struct Curl_easy *data,
+                                       struct ssh_conn *sshc,
+                                       struct SSHPROTO *sshp)
+{
+  /* Work on getting the specified file */
+  if(sshc->sftp_file)
+    sftp_close(sshc->sftp_file);
+
+  sshc->sftp_file = sftp_open(sshc->sftp_session, sshp->path,
+                              O_RDONLY, (mode_t)data->set.new_file_perms);
+  if(!sshc->sftp_file) {
+    failf(data, "Could not open remote file for reading: %s",
+          ssh_get_error(sshc->ssh_session));
+
+    return myssh_to_SFTP_CLOSE(data, sshc);
+  }
+  sftp_file_set_nonblocking(sshc->sftp_file);
+  myssh_to(data, sshc, SSH_SFTP_DOWNLOAD_STAT);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data,
+                                       struct ssh_conn *sshc)
 {
   curl_off_t size;
   int rc = 0;
@@ -951,7 +1320,7 @@
 
     if(size < 0) {
       failf(data, "Bad file size (%" FMT_OFF_T ")", size);
-      MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+      rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
       return rc;
     }
     if(data->state.use_range) {
@@ -961,7 +1330,7 @@
 
       from_t = curlx_str_number(&p, &from, CURL_OFF_T_MAX);
       if(from_t == STRE_OVERFLOW) {
-        MOVE_TO_ERROR_STATE(CURLE_RANGE_ERROR);
+        rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR);
         return rc;
       }
       curlx_str_passblanks(&p);
@@ -985,7 +1354,7 @@
       if(from > size) {
         failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
               FMT_OFF_T ")", from, size);
-        MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+        rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
         return rc;
       }
       if(from > to) {
@@ -994,7 +1363,7 @@
       }
       else {
         if((to - from) == CURL_OFF_T_MAX) {
-          MOVE_TO_ERROR_STATE(CURLE_RANGE_ERROR);
+          rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR);
           return rc;
         }
         size = to - from + 1;
@@ -1002,7 +1371,7 @@
 
       rc = sftp_seek64(sshc->sftp_file, from);
       if(rc) {
-        MOVE_TO_SFTP_CLOSE_STATE();
+        rc = myssh_to_SFTP_CLOSE(data, sshc);
         return rc;
       }
     }
@@ -1018,7 +1387,7 @@
       if((curl_off_t)size < -data->state.resume_from) {
         failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
               FMT_OFF_T ")", data->state.resume_from, size);
-        MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+        rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
         return rc;
       }
       /* download from where? */
@@ -1029,7 +1398,7 @@
         failf(data, "Offset (%" FMT_OFF_T
               ") was beyond file size (%" FMT_OFF_T ")",
               data->state.resume_from, size);
-        MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+        rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME);
         return rc;
       }
     }
@@ -1041,7 +1410,7 @@
 
     rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
     if(rc) {
-      MOVE_TO_SFTP_CLOSE_STATE();
+      rc = myssh_to_SFTP_CLOSE(data, sshc);
       return rc;
     }
   }
@@ -1051,7 +1420,7 @@
     /* no data to transfer */
     Curl_xfer_setup_nop(data);
     infof(data, "File already completely downloaded");
-    myssh_state(data, sshc, SSH_STOP);
+    myssh_to(data, sshc, SSH_STOP);
     return rc;
   }
   Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
@@ -1059,17 +1428,468 @@
   /* not set by Curl_xfer_setup to preserve keepon bits */
   data->conn->writesockfd = data->conn->sockfd;
 
-  /* we want to use the _receiving_ function even when the socket turns
-     out writableable as the underlying libssh recv function will deal
-     with both accordingly */
-  data->state.select_bits = CURL_CSELECT_IN;
-
   sshc->sftp_recv_state = 0;
-  myssh_state(data, sshc, SSH_STOP);
+  myssh_to(data, sshc, SSH_STOP);
 
   return rc;
 }
 
+static int myssh_in_SFTP_CLOSE(struct Curl_easy *data,
+                               struct ssh_conn *sshc,
+                               struct SSHPROTO *sshp)
+{
+  if(sshc->sftp_file) {
+    sftp_close(sshc->sftp_file);
+    sshc->sftp_file = NULL;
+  }
+  Curl_safefree(sshp->path);
+
+  DEBUGF(infof(data, "SFTP DONE done"));
+
+  /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
+     After nextstate is executed, the control should come back to
+     SSH_SFTP_CLOSE to pass the correct result back  */
+  if(sshc->nextstate != SSH_NO_STATE &&
+     sshc->nextstate != SSH_SFTP_CLOSE) {
+    myssh_to(data, sshc, sshc->nextstate);
+    sshc->nextstate = SSH_SFTP_CLOSE;
+  }
+  else {
+    myssh_to(data, sshc, SSH_STOP);
+  }
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_SHUTDOWN(struct Curl_easy *data,
+                                  struct ssh_conn *sshc)
+{
+  /* during times we get here due to a broken transfer and then the
+     sftp_handle might not have been taken down so make sure that is done
+     before we proceed */
+  ssh_set_blocking(sshc->ssh_session, 0);
+#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
+  if(sshc->sftp_aio) {
+    sftp_aio_free(sshc->sftp_aio);
+    sshc->sftp_aio = NULL;
+  }
+#endif
+
+  if(sshc->sftp_file) {
+    sftp_close(sshc->sftp_file);
+    sshc->sftp_file = NULL;
+  }
+
+  if(sshc->sftp_session) {
+    sftp_free(sshc->sftp_session);
+    sshc->sftp_session = NULL;
+  }
+
+  SSH_STRING_FREE_CHAR(sshc->homedir);
+
+  myssh_to(data, sshc, SSH_SESSION_DISCONNECT);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_INIT(struct Curl_easy *data,
+                              struct ssh_conn *sshc)
+{
+  int rc;
+  ssh_set_blocking(sshc->ssh_session, 1);
+
+  sshc->sftp_session = sftp_new(sshc->ssh_session);
+  if(!sshc->sftp_session) {
+    failf(data, "Failure initializing sftp session: %s",
+          ssh_get_error(sshc->ssh_session));
+    return myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT);
+  }
+
+  rc = sftp_init(sshc->sftp_session);
+  if(rc != SSH_OK) {
+    failf(data, "Failure initializing sftp session: %s",
+          ssh_get_error(sshc->ssh_session));
+    return myssh_to_ERROR(data, sshc, sftp_error_to_CURLE(SSH_FX_FAILURE));
+  }
+  myssh_to(data, sshc, SSH_SFTP_REALPATH);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_REALPATH(struct Curl_easy *data,
+                                  struct ssh_conn *sshc)
+{
+  /* Get the "home" directory */
+  sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
+  if(!sshc->homedir)
+    return myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT);
+
+  free(data->state.most_recent_ftp_entrypath);
+  data->state.most_recent_ftp_entrypath = strdup(sshc->homedir);
+  if(!data->state.most_recent_ftp_entrypath)
+    return myssh_to_ERROR(data, sshc, CURLE_OUT_OF_MEMORY);
+
+  /* This is the last step in the SFTP connect phase. Do note that while
+     we get the homedir here, we get the "workingpath" in the DO action
+     since the homedir will remain the same between request but the
+     working path will not. */
+  DEBUGF(infof(data, "SSH CONNECT phase done"));
+  myssh_to(data, sshc, SSH_STOP);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_QUOTE_INIT(struct Curl_easy *data,
+                                    struct ssh_conn *sshc,
+                                    struct SSHPROTO *sshp)
+{
+  CURLcode result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
+  if(result) {
+    sshc->actualcode = result;
+    myssh_to(data, sshc, SSH_STOP);
+  }
+  else if(data->set.quote) {
+    infof(data, "Sending quote commands");
+    sshc->quote_item = data->set.quote;
+    myssh_to(data, sshc, SSH_SFTP_QUOTE);
+  }
+  else
+    myssh_to(data, sshc, SSH_SFTP_GETINFO);
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_POSTQUOTE_INIT(struct Curl_easy *data,
+                                        struct ssh_conn *sshc)
+{
+  if(data->set.postquote) {
+    infof(data, "Sending quote commands");
+    sshc->quote_item = data->set.postquote;
+    myssh_to(data, sshc, SSH_SFTP_QUOTE);
+  }
+  else {
+    myssh_to(data, sshc, SSH_STOP);
+  }
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_QUOTE(struct Curl_easy *data,
+                               struct ssh_conn *sshc,
+                               struct SSHPROTO *sshp)
+{
+  const char *cp;
+  CURLcode result;
+
+  /*
+   * Support some of the "FTP" commands
+   */
+  char *cmd = sshc->quote_item->data;
+  sshc->acceptfail = FALSE;
+
+  /* if a command starts with an asterisk, which a legal SFTP command never
+     can, the command will be allowed to fail without it causing any
+     aborts or cancels etc. It will cause libcurl to act as if the command
+     is successful, whatever the server responds. */
+
+  if(cmd[0] == '*') {
+    cmd++;
+    sshc->acceptfail = TRUE;
+  }
+
+  if(curl_strequal("pwd", cmd)) {
+    /* output debug output if that is requested */
+    char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path);
+    if(!tmp) {
+      sshc->actualcode = CURLE_OUT_OF_MEMORY;
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      return SSH_NO_ERROR;
+    }
+    Curl_debug(data, CURLINFO_HEADER_OUT, "PWD\n", 4);
+    Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
+
+    /* this sends an FTP-like "header" to the header callback so that the
+       current directory can be read very similar to how it is read when
+       using ordinary FTP. */
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+    free(tmp);
+    if(result) {
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+    }
+    else
+      myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
+    return SSH_NO_ERROR;
+  }
+
+  /*
+   * the arguments following the command must be separated from the
+   * command with a space so we can check for it unconditionally
+   */
+  cp = strchr(cmd, ' ');
+  if(!cp) {
+    failf(data, "Syntax error in SFTP command. Supply parameter(s)");
+    myssh_to(data, sshc, SSH_SFTP_CLOSE);
+    sshc->nextstate = SSH_NO_STATE;
+    sshc->actualcode = CURLE_QUOTE_ERROR;
+    return SSH_NO_ERROR;
+  }
+
+  /*
+   * also, every command takes at least one argument so we get that
+   * first argument right now
+   */
+  result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
+  if(result) {
+    if(result == CURLE_OUT_OF_MEMORY)
+      failf(data, "Out of memory");
+    else
+      failf(data, "Syntax error: Bad first parameter");
+    myssh_to(data, sshc, SSH_SFTP_CLOSE);
+    sshc->nextstate = SSH_NO_STATE;
+    sshc->actualcode = result;
+    return SSH_NO_ERROR;
+  }
+
+  /*
+   * SFTP is a binary protocol, so we do not send text commands
+   * to the server. Instead, we scan for commands used by
+   * OpenSSH's sftp program and call the appropriate libssh
+   * functions.
+   */
+  if(!strncmp(cmd, "chgrp ", 6) ||
+     !strncmp(cmd, "chmod ", 6) ||
+     !strncmp(cmd, "chown ", 6) ||
+     !strncmp(cmd, "atime ", 6) ||
+     !strncmp(cmd, "mtime ", 6)) {
+    /* attribute change */
+
+    /* sshc->quote_path1 contains the mode to set */
+    /* get the destination */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result == CURLE_OUT_OF_MEMORY)
+        failf(data, "Out of memory");
+      else
+        failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
+              "Bad second parameter");
+      Curl_safefree(sshc->quote_path1);
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+      return SSH_NO_ERROR;
+    }
+    sshc->quote_attrs = NULL;
+    myssh_to(data, sshc, SSH_SFTP_QUOTE_STAT);
+    return SSH_NO_ERROR;
+  }
+  if(!strncmp(cmd, "ln ", 3) ||
+     !strncmp(cmd, "symlink ", 8)) {
+    /* symbolic linking */
+    /* sshc->quote_path1 is the source */
+    /* get the destination */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result == CURLE_OUT_OF_MEMORY)
+        failf(data, "Out of memory");
+      else
+        failf(data, "Syntax error in ln/symlink: Bad second parameter");
+      Curl_safefree(sshc->quote_path1);
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+      return SSH_NO_ERROR;
+    }
+    myssh_to(data, sshc, SSH_SFTP_QUOTE_SYMLINK);
+    return SSH_NO_ERROR;
+  }
+  else if(!strncmp(cmd, "mkdir ", 6)) {
+    /* create dir */
+    myssh_to(data, sshc, SSH_SFTP_QUOTE_MKDIR);
+    return SSH_NO_ERROR;
+  }
+  else if(!strncmp(cmd, "rename ", 7)) {
+    /* rename file */
+    /* first param is the source path */
+    /* second param is the dest. path */
+    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
+    if(result) {
+      if(result == CURLE_OUT_OF_MEMORY)
+        failf(data, "Out of memory");
+      else
+        failf(data, "Syntax error in rename: Bad second parameter");
+      Curl_safefree(sshc->quote_path1);
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = result;
+      return SSH_NO_ERROR;
+    }
+    myssh_to(data, sshc, SSH_SFTP_QUOTE_RENAME);
+    return SSH_NO_ERROR;
+  }
+  else if(!strncmp(cmd, "rmdir ", 6)) {
+    /* delete dir */
+    myssh_to(data, sshc, SSH_SFTP_QUOTE_RMDIR);
+    return SSH_NO_ERROR;
+  }
+  else if(!strncmp(cmd, "rm ", 3)) {
+    myssh_to(data, sshc, SSH_SFTP_QUOTE_UNLINK);
+    return SSH_NO_ERROR;
+  }
+#ifdef HAS_STATVFS_SUPPORT
+  else if(!strncmp(cmd, "statvfs ", 8)) {
+    myssh_to(data, sshc, SSH_SFTP_QUOTE_STATVFS);
+    return SSH_NO_ERROR;
+  }
+#endif
+
+  failf(data, "Unknown SFTP command");
+  Curl_safefree(sshc->quote_path1);
+  Curl_safefree(sshc->quote_path2);
+  myssh_to(data, sshc, SSH_SFTP_CLOSE);
+  sshc->nextstate = SSH_NO_STATE;
+  sshc->actualcode = CURLE_QUOTE_ERROR;
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_NEXT_QUOTE(struct Curl_easy *data,
+                                    struct ssh_conn *sshc)
+{
+  Curl_safefree(sshc->quote_path1);
+  Curl_safefree(sshc->quote_path2);
+
+  sshc->quote_item = sshc->quote_item->next;
+
+  if(sshc->quote_item) {
+    myssh_to(data, sshc, SSH_SFTP_QUOTE);
+  }
+  else {
+    if(sshc->nextstate != SSH_NO_STATE) {
+      myssh_to(data, sshc, sshc->nextstate);
+      sshc->nextstate = SSH_NO_STATE;
+    }
+    else {
+      myssh_to(data, sshc, SSH_SFTP_GETINFO);
+    }
+  }
+  return SSH_NO_ERROR;
+}
+
+static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data,
+                                    struct ssh_conn *sshc)
+{
+  char *cmd = sshc->quote_item->data;
+  sshc->acceptfail = FALSE;
+
+  /* if a command starts with an asterisk, which a legal SFTP command never
+     can, the command will be allowed to fail without it causing any
+     aborts or cancels etc. It will cause libcurl to act as if the command
+     is successful, whatever the server responds. */
+
+  if(cmd[0] == '*') {
+    cmd++;
+    sshc->acceptfail = TRUE;
+  }
+
+  /* We read the file attributes, store them in sshc->quote_attrs
+   * and modify them accordingly to command. Then we switch to
+   * QUOTE_SETSTAT state to write new ones.
+   */
+
+  if(sshc->quote_attrs)
+    sftp_attributes_free(sshc->quote_attrs);
+  sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
+  if(!sshc->quote_attrs) {
+    Curl_safefree(sshc->quote_path1);
+    Curl_safefree(sshc->quote_path2);
+    failf(data, "Attempt to get SFTP stats failed: %d",
+          sftp_get_error(sshc->sftp_session));
+    myssh_to(data, sshc, SSH_SFTP_CLOSE);
+    sshc->nextstate = SSH_NO_STATE;
+    sshc->actualcode = CURLE_QUOTE_ERROR;
+    return SSH_NO_ERROR;
+  }
+
+  /* Now set the new attributes... */
+  if(!strncmp(cmd, "chgrp", 5)) {
+    const char *p = sshc->quote_path1;
+    curl_off_t gid;
+    (void)curlx_str_number(&p, &gid, UINT_MAX);
+    sshc->quote_attrs->gid = (uint32_t)gid;
+    if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+       !sshc->acceptfail) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      failf(data, "Syntax error: chgrp gid not a number");
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return SSH_NO_ERROR;
+    }
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
+  }
+  else if(!strncmp(cmd, "chmod", 5)) {
+    curl_off_t perms;
+    const char *p = sshc->quote_path1;
+    if(curlx_str_octal(&p, &perms, 07777)) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      failf(data, "Syntax error: chmod permissions not a number");
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return SSH_NO_ERROR;
+    }
+    sshc->quote_attrs->permissions = (mode_t)perms;
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
+  }
+  else if(!strncmp(cmd, "chown", 5)) {
+    const char *p = sshc->quote_path1;
+    curl_off_t uid;
+    (void)curlx_str_number(&p, &uid, UINT_MAX);
+    if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+       !sshc->acceptfail) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      failf(data, "Syntax error: chown uid not a number");
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return SSH_NO_ERROR;
+    }
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
+  }
+  else if(!strncmp(cmd, "atime", 5) ||
+          !strncmp(cmd, "mtime", 5)) {
+    time_t date = Curl_getdate_capped(sshc->quote_path1);
+    bool fail = FALSE;
+    if(date == -1) {
+      failf(data, "incorrect date format for %.*s", 5, cmd);
+      fail = TRUE;
+    }
+#if SIZEOF_TIME_T > 4
+    else if(date > 0xffffffff) {
+      failf(data, "date overflow");
+      fail = TRUE; /* avoid setting a capped time */
+    }
+#endif
+    if(fail) {
+      Curl_safefree(sshc->quote_path1);
+      Curl_safefree(sshc->quote_path2);
+      myssh_to(data, sshc, SSH_SFTP_CLOSE);
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_QUOTE_ERROR;
+      return SSH_NO_ERROR;
+    }
+    if(!strncmp(cmd, "atime", 5))
+      sshc->quote_attrs->atime = (uint32_t)date;
+    else /* mtime */
+      sshc->quote_attrs->mtime = (uint32_t)date;
+
+    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
+  }
+
+  /* Now send the completed structure... */
+  myssh_to(data, sshc, SSH_SFTP_QUOTE_SETSTAT);
+  return SSH_NO_ERROR;
+}
+
 /*
  * ssh_statemach_act() runs the SSH state machine as far as it can without
  * blocking and without reaching the end. The data the pointer 'block' points
@@ -1083,253 +1903,76 @@
 {
   CURLcode result = CURLE_OK;
   struct connectdata *conn = data->conn;
-  curl_socket_t sock = conn->sock[FIRSTSOCKET];
   int rc = SSH_NO_ERROR, err;
   const char *err_msg;
-  *block = 0;                   /* we are not blocking by default */
 
+  *block = FALSE;                   /* we are not blocking by default */
   do {
 
     switch(sshc->state) {
     case SSH_INIT:
       myssh_state_init(data, sshc);
       FALLTHROUGH();
-
     case SSH_S_STARTUP:
-      rc = myssh_state_startup(data, sshc);
+      rc = myssh_in_S_STARTUP(data, sshc);
       if(rc)
         break;
       FALLTHROUGH();
     case SSH_HOSTKEY:
       rc = myssh_is_known(data, sshc);
       if(rc != SSH_OK) {
-        MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
+        rc = myssh_to_ERROR(data, sshc, CURLE_PEER_FAILED_VERIFICATION);
         break;
       }
-
-      myssh_state(data, sshc, SSH_AUTHLIST);
+      myssh_to(data, sshc, SSH_AUTHLIST);
       FALLTHROUGH();
     case SSH_AUTHLIST:
-      rc = myssh_state_authlist(data, sshc);
+      rc = myssh_in_AUTHLIST(data, sshc);
       break;
     case SSH_AUTH_PKEY_INIT:
-      rc = myssh_state_auth_pkey_init(data, sshc);
+      rc = myssh_in_AUTH_PKEY_INIT(data, sshc);
       break;
     case SSH_AUTH_PKEY:
-      rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey);
-      if(rc == SSH_AUTH_AGAIN) {
-        rc = SSH_AGAIN;
-        break;
-      }
-
-      if(rc == SSH_AUTH_SUCCESS) {
-        sshc->authed = TRUE;
-        infof(data, "Completed public key authentication");
-        myssh_state(data, sshc, SSH_AUTH_DONE);
-        break;
-      }
-      else {
-        infof(data, "Failed public key authentication (rc: %d)", rc);
-        MOVE_TO_GSSAPI_AUTH;
-      }
+      rc = myssh_in_AUTH_PKEY(data, sshc);
       break;
-
     case SSH_AUTH_GSSAPI:
-      if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
-        MOVE_TO_KEY_AUTH;
-        break;
-      }
-
-      rc = ssh_userauth_gssapi(sshc->ssh_session);
-      if(rc == SSH_AUTH_AGAIN) {
-        rc = SSH_AGAIN;
-        break;
-      }
-
-      if(rc == SSH_AUTH_SUCCESS) {
-        rc = SSH_OK;
-        sshc->authed = TRUE;
-        infof(data, "Completed gssapi authentication");
-        myssh_state(data, sshc, SSH_AUTH_DONE);
-        break;
-      }
-
-      MOVE_TO_KEY_AUTH;
+      rc = myssh_in_AUTH_GSSAPI(data, sshc);
       break;
-
     case SSH_AUTH_KEY_INIT:
-      if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) {
-        myssh_state(data, sshc, SSH_AUTH_KEY);
-      }
-      else {
-        MOVE_TO_PASSWD_AUTH;
-      }
+      rc = myssh_in_AUTH_KEY_INIT(data, sshc);
       break;
-
     case SSH_AUTH_KEY:
-      /* keyboard-interactive authentication */
-      rc = myssh_auth_interactive(conn, sshc);
-      if(rc == SSH_AGAIN) {
-        break;
-      }
-      if(rc == SSH_OK) {
-        sshc->authed = TRUE;
-        infof(data, "completed keyboard interactive authentication");
-        myssh_state(data, sshc, SSH_AUTH_DONE);
-      }
-      else {
-        MOVE_TO_PASSWD_AUTH;
-      }
+      rc = myssh_in_AUTH_KEY(data, sshc);
       break;
-
     case SSH_AUTH_PASS_INIT:
-      if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
-        MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
-        break;
-      }
-      myssh_state(data, sshc, SSH_AUTH_PASS);
-      FALLTHROUGH();
-
+      rc = myssh_in_AUTH_PASS_INIT(data, sshc);
+      break;
     case SSH_AUTH_PASS:
-      rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
-      if(rc == SSH_AUTH_AGAIN) {
-        rc = SSH_AGAIN;
-        break;
-      }
-
-      if(rc == SSH_AUTH_SUCCESS) {
-        sshc->authed = TRUE;
-        infof(data, "Completed password authentication");
-        myssh_state(data, sshc, SSH_AUTH_DONE);
-      }
-      else {
-        MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
-      }
+      rc = myssh_in_AUTH_PASS(data, sshc);
       break;
-
     case SSH_AUTH_DONE:
-      if(!sshc->authed) {
-        failf(data, "Authentication failure");
-        MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
-        break;
-      }
-
-      /*
-       * At this point we have an authenticated ssh session.
-       */
-      infof(data, "Authentication complete");
-
-      Curl_pgrsTime(data, TIMER_APPCONNECT);      /* SSH is connected */
-
-      conn->sockfd = sock;
-      conn->writesockfd = CURL_SOCKET_BAD;
-
-      if(conn->handler->protocol == CURLPROTO_SFTP) {
-        myssh_state(data, sshc, SSH_SFTP_INIT);
-        break;
-      }
-      infof(data, "SSH CONNECT phase done");
-      myssh_state(data, sshc, SSH_STOP);
+      rc = myssh_in_AUTH_DONE(data, sshc);
       break;
-
     case SSH_SFTP_INIT:
-      ssh_set_blocking(sshc->ssh_session, 1);
-
-      sshc->sftp_session = sftp_new(sshc->ssh_session);
-      if(!sshc->sftp_session) {
-        failf(data, "Failure initializing sftp session: %s",
-              ssh_get_error(sshc->ssh_session));
-        MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
-        break;
-      }
-
-      rc = sftp_init(sshc->sftp_session);
-      if(rc != SSH_OK) {
-        failf(data, "Failure initializing sftp session: %s",
-              ssh_get_error(sshc->ssh_session));
-        MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE));
-        break;
-      }
-      myssh_state(data, sshc, SSH_SFTP_REALPATH);
-      FALLTHROUGH();
+      rc = myssh_in_SFTP_INIT(data, sshc);
+      break;
     case SSH_SFTP_REALPATH:
-      /*
-       * Get the "home" directory
-       */
-      sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
-      if(!sshc->homedir) {
-        MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
-        break;
-      }
-      free(data->state.most_recent_ftp_entrypath);
-      data->state.most_recent_ftp_entrypath = strdup(sshc->homedir);
-      if(!data->state.most_recent_ftp_entrypath)
-        return CURLE_OUT_OF_MEMORY;
-
-      /* This is the last step in the SFTP connect phase. Do note that while
-         we get the homedir here, we get the "workingpath" in the DO action
-         since the homedir will remain the same between request but the
-         working path will not. */
-      DEBUGF(infof(data, "SSH CONNECT phase done"));
-      myssh_state(data, sshc, SSH_STOP);
+      rc = myssh_in_SFTP_REALPATH(data, sshc);
       break;
-
     case SSH_SFTP_QUOTE_INIT:
-      result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
-      if(result) {
-        sshc->actualcode = result;
-        myssh_state(data, sshc, SSH_STOP);
-        break;
-      }
-
-      if(data->set.quote) {
-        infof(data, "Sending quote commands");
-        sshc->quote_item = data->set.quote;
-        myssh_state(data, sshc, SSH_SFTP_QUOTE);
-      }
-      else {
-        myssh_state(data, sshc, SSH_SFTP_GETINFO);
-      }
+      rc = myssh_in_SFTP_QUOTE_INIT(data, sshc, sshp);
       break;
-
     case SSH_SFTP_POSTQUOTE_INIT:
-      if(data->set.postquote) {
-        infof(data, "Sending quote commands");
-        sshc->quote_item = data->set.postquote;
-        myssh_state(data, sshc, SSH_SFTP_QUOTE);
-      }
-      else {
-        myssh_state(data, sshc, SSH_STOP);
-      }
+      rc = myssh_in_SFTP_POSTQUOTE_INIT(data, sshc);
       break;
-
     case SSH_SFTP_QUOTE:
-      /* Send any quote commands */
-      sftp_quote(data, sshc, sshp);
+      rc = myssh_in_SFTP_QUOTE(data, sshc, sshp);
       break;
-
     case SSH_SFTP_NEXT_QUOTE:
-      Curl_safefree(sshc->quote_path1);
-      Curl_safefree(sshc->quote_path2);
-
-      sshc->quote_item = sshc->quote_item->next;
-
-      if(sshc->quote_item) {
-        myssh_state(data, sshc, SSH_SFTP_QUOTE);
-      }
-      else {
-        if(sshc->nextstate != SSH_NO_STATE) {
-          myssh_state(data, sshc, sshc->nextstate);
-          sshc->nextstate = SSH_NO_STATE;
-        }
-        else {
-          myssh_state(data, sshc, SSH_SFTP_GETINFO);
-        }
-      }
+      rc = myssh_in_SFTP_NEXT_QUOTE(data, sshc);
       break;
-
     case SSH_SFTP_QUOTE_STAT:
-      sftp_quote_stat(data, sshc);
+      rc = myssh_in_SFTP_QUOTE_STAT(data, sshc);
       break;
 
     case SSH_SFTP_QUOTE_SETSTAT:
@@ -1340,7 +1983,7 @@
         Curl_safefree(sshc->quote_path2);
         failf(data, "Attempt to set SFTP stats failed: %s",
               ssh_get_error(sshc->ssh_session));
-        myssh_state(data, sshc, SSH_SFTP_CLOSE);
+        myssh_to(data, sshc, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         /* sshc->actualcode = sftp_error_to_CURLE(err);
@@ -1348,7 +1991,7 @@
          * the error the libssh2 backend is returning */
         break;
       }
-      myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
+      myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_SYMLINK:
@@ -1359,12 +2002,12 @@
         Curl_safefree(sshc->quote_path2);
         failf(data, "symlink command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        myssh_state(data, sshc, SSH_SFTP_CLOSE);
+        myssh_to(data, sshc, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
+      myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_MKDIR:
@@ -1374,12 +2017,12 @@
         Curl_safefree(sshc->quote_path1);
         failf(data, "mkdir command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        myssh_state(data, sshc, SSH_SFTP_CLOSE);
+        myssh_to(data, sshc, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
+      myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_RENAME:
@@ -1390,12 +2033,12 @@
         Curl_safefree(sshc->quote_path2);
         failf(data, "rename command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        myssh_state(data, sshc, SSH_SFTP_CLOSE);
+        myssh_to(data, sshc, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
+      myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_RMDIR:
@@ -1404,12 +2047,12 @@
         Curl_safefree(sshc->quote_path1);
         failf(data, "rmdir command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        myssh_state(data, sshc, SSH_SFTP_CLOSE);
+        myssh_to(data, sshc, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
+      myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_UNLINK:
@@ -1418,84 +2061,28 @@
         Curl_safefree(sshc->quote_path1);
         failf(data, "rm command failed: %s",
               ssh_get_error(sshc->ssh_session));
-        myssh_state(data, sshc, SSH_SFTP_CLOSE);
+        myssh_to(data, sshc, SSH_SFTP_CLOSE);
         sshc->nextstate = SSH_NO_STATE;
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
+      myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE);
       break;
 
     case SSH_SFTP_QUOTE_STATVFS:
-    {
-      sftp_statvfs_t statvfs;
-
-      statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1);
-      if(!statvfs && !sshc->acceptfail) {
-        Curl_safefree(sshc->quote_path1);
-        failf(data, "statvfs command failed: %s",
-              ssh_get_error(sshc->ssh_session));
-        myssh_state(data, sshc, SSH_SFTP_CLOSE);
-        sshc->nextstate = SSH_NO_STATE;
-        sshc->actualcode = CURLE_QUOTE_ERROR;
-        break;
-      }
-      else if(statvfs) {
-        #ifdef _MSC_VER
-        #define CURL_LIBSSH_VFS_SIZE_MASK "I64u"
-        #else
-        #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64
-        #endif
-        char *tmp = aprintf("statvfs:\n"
-                            "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
-                            "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n",
-                            statvfs->f_bsize, statvfs->f_frsize,
-                            statvfs->f_blocks, statvfs->f_bfree,
-                            statvfs->f_bavail, statvfs->f_files,
-                            statvfs->f_ffree, statvfs->f_favail,
-                            statvfs->f_fsid, statvfs->f_flag,
-                            statvfs->f_namemax);
-        sftp_statvfs_free(statvfs);
-
-        if(!tmp) {
-          result = CURLE_OUT_OF_MEMORY;
-          myssh_state(data, sshc, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          break;
-        }
-
-        result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
-        free(tmp);
-        if(result) {
-          myssh_state(data, sshc, SSH_SFTP_CLOSE);
-          sshc->nextstate = SSH_NO_STATE;
-          sshc->actualcode = result;
-        }
-      }
-      myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
+      rc = myssh_in_SFTP_QUOTE_STATVFS(data, sshc);
       break;
-    }
 
     case SSH_SFTP_GETINFO:
       if(data->set.get_filetime) {
-        myssh_state(data, sshc, SSH_SFTP_FILETIME);
+        myssh_to(data, sshc, SSH_SFTP_FILETIME);
       }
       else {
-        myssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
+        myssh_to(data, sshc, SSH_SFTP_TRANS_INIT);
       }
       break;
 
-    case SSH_SFTP_FILETIME:
-    {
+    case SSH_SFTP_FILETIME: {
       sftp_attributes attrs;
 
       attrs = sftp_stat(sshc->sftp_session, sshp->path);
@@ -1504,32 +2091,32 @@
         sftp_attributes_free(attrs);
       }
 
-      myssh_state(data, sshc, SSH_SFTP_TRANS_INIT);
+      myssh_to(data, sshc, SSH_SFTP_TRANS_INIT);
       break;
     }
 
     case SSH_SFTP_TRANS_INIT:
       if(data->state.upload)
-        myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
+        myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT);
       else {
         if(sshp->path[strlen(sshp->path)-1] == '/')
-          myssh_state(data, sshc, SSH_SFTP_READDIR_INIT);
+          myssh_to(data, sshc, SSH_SFTP_READDIR_INIT);
         else
-          myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT);
+          myssh_to(data, sshc, SSH_SFTP_DOWNLOAD_INIT);
       }
       break;
 
     case SSH_SFTP_UPLOAD_INIT:
-      rc = myssh_state_upload_init(data, sshc, sshp);
+      rc = myssh_in_UPLOAD_INIT(data, sshc, sshp);
       break;
 
     case SSH_SFTP_CREATE_DIRS_INIT:
       if(strlen(sshp->path) > 1) {
         sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
-        myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS);
+        myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS);
       }
       else {
-        myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
+        myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT);
       }
       break;
 
@@ -1539,10 +2126,10 @@
         *sshc->slash_pos = 0;
 
         infof(data, "Creating directory '%s'", sshp->path);
-        myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR);
+        myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR);
         break;
       }
-      myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT);
+      myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT);
       break;
 
     case SSH_SFTP_CREATE_DIRS_MKDIR:
@@ -1561,254 +2148,47 @@
         if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
            (err != SSH_FX_FAILURE) &&
            (err != SSH_FX_PERMISSION_DENIED)) {
-          MOVE_TO_SFTP_CLOSE_STATE();
+          rc = myssh_to_SFTP_CLOSE(data, sshc);
           break;
         }
         rc = 0; /* clear rc and continue */
       }
-      myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS);
+      myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS);
       break;
 
     case SSH_SFTP_READDIR_INIT:
-      Curl_pgrsSetDownloadSize(data, -1);
-      if(data->req.no_body) {
-        myssh_state(data, sshc, SSH_STOP);
-        break;
-      }
-
-      /*
-       * This is a directory that we are trying to get, so produce a directory
-       * listing
-       */
-      sshc->sftp_dir = sftp_opendir(sshc->sftp_session,
-                                    sshp->path);
-      if(!sshc->sftp_dir) {
-        failf(data, "Could not open directory for reading: %s",
-              ssh_get_error(sshc->ssh_session));
-        MOVE_TO_SFTP_CLOSE_STATE();
-        break;
-      }
-      myssh_state(data, sshc, SSH_SFTP_READDIR);
+      rc = myssh_in_SFTP_READDIR_INIT(data, sshc, sshp);
       break;
-
     case SSH_SFTP_READDIR:
-      curlx_dyn_reset(&sshc->readdir_buf);
-      if(sshc->readdir_attrs)
-        sftp_attributes_free(sshc->readdir_attrs);
-
-      sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir);
-      if(sshc->readdir_attrs) {
-        sshc->readdir_filename = sshc->readdir_attrs->name;
-        sshc->readdir_longentry = sshc->readdir_attrs->longname;
-        sshc->readdir_len = strlen(sshc->readdir_filename);
-
-        if(data->set.list_only) {
-          char *tmpLine;
-
-          tmpLine = aprintf("%s\n", sshc->readdir_filename);
-          if(!tmpLine) {
-            myssh_state(data, sshc, SSH_SFTP_CLOSE);
-            sshc->actualcode = CURLE_OUT_OF_MEMORY;
-            break;
-          }
-          result = Curl_client_write(data, CLIENTWRITE_BODY,
-                                     tmpLine, sshc->readdir_len + 1);
-          free(tmpLine);
-
-          if(result) {
-            myssh_state(data, sshc, SSH_STOP);
-            break;
-          }
-
-        }
-        else {
-          if(curlx_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
-            sshc->actualcode = CURLE_OUT_OF_MEMORY;
-            myssh_state(data, sshc, SSH_STOP);
-            break;
-          }
-
-          if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
-             ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
-              SSH_S_IFLNK)) {
-            sshc->readdir_linkPath = aprintf("%s%s", sshp->path,
-                                             sshc->readdir_filename);
-
-            if(!sshc->readdir_linkPath) {
-              myssh_state(data, sshc, SSH_SFTP_CLOSE);
-              sshc->actualcode = CURLE_OUT_OF_MEMORY;
-              break;
-            }
-
-            myssh_state(data, sshc, SSH_SFTP_READDIR_LINK);
-            break;
-          }
-          myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM);
-          break;
-        }
-      }
-      else if(sftp_dir_eof(sshc->sftp_dir)) {
-        myssh_state(data, sshc, SSH_SFTP_READDIR_DONE);
-        break;
-      }
-      else {
-        failf(data, "Could not open remote file for reading: %s",
-              ssh_get_error(sshc->ssh_session));
-        MOVE_TO_SFTP_CLOSE_STATE();
-        break;
-      }
+      rc = myssh_in_SFTP_READDIR(data, sshc, sshp);
       break;
-
     case SSH_SFTP_READDIR_LINK:
-      if(sshc->readdir_link_attrs)
-        sftp_attributes_free(sshc->readdir_link_attrs);
-
-      sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session,
-                                            sshc->readdir_linkPath);
-      if(sshc->readdir_link_attrs == 0) {
-        failf(data, "Could not read symlink for reading: %s",
-              ssh_get_error(sshc->ssh_session));
-        MOVE_TO_SFTP_CLOSE_STATE();
-        break;
-      }
-
-      if(!sshc->readdir_link_attrs->name) {
-        sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
-                                          sshc->readdir_linkPath);
-        if(!sshc->readdir_filename)
-          sshc->readdir_len = 0;
-        else
-          sshc->readdir_len = strlen(sshc->readdir_tmp);
-        sshc->readdir_longentry = NULL;
-        sshc->readdir_filename = sshc->readdir_tmp;
-      }
-      else {
-        sshc->readdir_len = strlen(sshc->readdir_link_attrs->name);
-        sshc->readdir_filename = sshc->readdir_link_attrs->name;
-        sshc->readdir_longentry = sshc->readdir_link_attrs->longname;
-      }
-
-      Curl_safefree(sshc->readdir_linkPath);
-
-      if(curlx_dyn_addf(&sshc->readdir_buf, " -> %s",
-                        sshc->readdir_filename)) {
-        sshc->actualcode = CURLE_OUT_OF_MEMORY;
-        break;
-      }
-
-      sftp_attributes_free(sshc->readdir_link_attrs);
-      sshc->readdir_link_attrs = NULL;
-      sshc->readdir_filename = NULL;
-      sshc->readdir_longentry = NULL;
-
-      myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM);
-      FALLTHROUGH();
+      rc = myssh_in_SFTP_READDIR_LINK(data, sshc);
+      break;
     case SSH_SFTP_READDIR_BOTTOM:
-      if(curlx_dyn_addn(&sshc->readdir_buf, "\n", 1))
-        result = CURLE_OUT_OF_MEMORY;
-      else
-        result = Curl_client_write(data, CLIENTWRITE_BODY,
-                                   curlx_dyn_ptr(&sshc->readdir_buf),
-                                   curlx_dyn_len(&sshc->readdir_buf));
-
-      ssh_string_free_char(sshc->readdir_tmp);
-      sshc->readdir_tmp = NULL;
-
-      if(result) {
-        myssh_state(data, sshc, SSH_STOP);
-      }
-      else
-        myssh_state(data, sshc, SSH_SFTP_READDIR);
+      rc = myssh_in_SFTP_READDIR_BOTTOM(data, sshc);
       break;
-
     case SSH_SFTP_READDIR_DONE:
-      sftp_closedir(sshc->sftp_dir);
-      sshc->sftp_dir = NULL;
-
-      /* no data to transfer */
-      Curl_xfer_setup_nop(data);
-      myssh_state(data, sshc, SSH_STOP);
+      rc = myssh_in_SFTP_READDIR_DONE(data, sshc);
       break;
-
     case SSH_SFTP_DOWNLOAD_INIT:
-      /*
-       * Work on getting the specified file
-       */
-      if(sshc->sftp_file)
-        sftp_close(sshc->sftp_file);
-
-      sshc->sftp_file = sftp_open(sshc->sftp_session, sshp->path,
-                                  O_RDONLY, (mode_t)data->set.new_file_perms);
-      if(!sshc->sftp_file) {
-        failf(data, "Could not open remote file for reading: %s",
-              ssh_get_error(sshc->ssh_session));
-
-        MOVE_TO_SFTP_CLOSE_STATE();
-        break;
-      }
-      sftp_file_set_nonblocking(sshc->sftp_file);
-      myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT);
+      rc = myssh_in_SFTP_DOWNLOAD_INIT(data, sshc, sshp);
       break;
-
     case SSH_SFTP_DOWNLOAD_STAT:
-      rc = myssh_state_sftp_download_stat(data, sshc);
+      rc = myssh_in_SFTP_DOWNLOAD_STAT(data, sshc);
       break;
-
     case SSH_SFTP_CLOSE:
-      if(sshc->sftp_file) {
-        sftp_close(sshc->sftp_file);
-        sshc->sftp_file = NULL;
-      }
-      Curl_safefree(sshp->path);
-
-      DEBUGF(infof(data, "SFTP DONE done"));
-
-      /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
-         After nextstate is executed, the control should come back to
-         SSH_SFTP_CLOSE to pass the correct result back  */
-      if(sshc->nextstate != SSH_NO_STATE &&
-         sshc->nextstate != SSH_SFTP_CLOSE) {
-        myssh_state(data, sshc, sshc->nextstate);
-        sshc->nextstate = SSH_SFTP_CLOSE;
-      }
-      else {
-        myssh_state(data, sshc, SSH_STOP);
-        result = sshc->actualcode;
-      }
+      rc = myssh_in_SFTP_CLOSE(data, sshc, sshp);
       break;
-
     case SSH_SFTP_SHUTDOWN:
-      /* during times we get here due to a broken transfer and then the
-         sftp_handle might not have been taken down so make sure that is done
-         before we proceed */
-      ssh_set_blocking(sshc->ssh_session, 0);
-#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0)
-      if(sshc->sftp_aio) {
-        sftp_aio_free(sshc->sftp_aio);
-        sshc->sftp_aio = NULL;
-      }
-#endif
-
-      if(sshc->sftp_file) {
-        sftp_close(sshc->sftp_file);
-        sshc->sftp_file = NULL;
-      }
-
-      if(sshc->sftp_session) {
-        sftp_free(sshc->sftp_session);
-        sshc->sftp_session = NULL;
-      }
-
-      SSH_STRING_FREE_CHAR(sshc->homedir);
-
-      myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
+      rc = myssh_in_SFTP_SHUTDOWN(data, sshc);
       break;
 
     case SSH_SCP_TRANS_INIT:
       result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
       if(result) {
         sshc->actualcode = result;
-        myssh_state(data, sshc, SSH_STOP);
+        myssh_to(data, sshc, SSH_STOP);
         break;
       }
 
@@ -1819,26 +2199,25 @@
         if(data->state.infilesize < 0) {
           failf(data, "SCP requires a known file size for upload");
           sshc->actualcode = CURLE_UPLOAD_FAILED;
-          MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+          rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
           break;
         }
 
         sshc->scp_session =
           ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, sshp->path);
-        myssh_state(data, sshc, SSH_SCP_UPLOAD_INIT);
+        myssh_to(data, sshc, SSH_SCP_UPLOAD_INIT);
       }
       else {
         sshc->scp_session =
           ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, sshp->path);
-        myssh_state(data, sshc, SSH_SCP_DOWNLOAD_INIT);
+        myssh_to(data, sshc, SSH_SCP_DOWNLOAD_INIT);
       }
 
       if(!sshc->scp_session) {
         err_msg = ssh_get_error(sshc->ssh_session);
         failf(data, "%s", err_msg);
-        MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+        rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
       }
-
       break;
 
     case SSH_SCP_UPLOAD_INIT:
@@ -1847,7 +2226,7 @@
       if(rc != SSH_OK) {
         err_msg = ssh_get_error(sshc->ssh_session);
         failf(data, "%s", err_msg);
-        MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+        rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
         break;
       }
 
@@ -1858,7 +2237,7 @@
       if(rc != SSH_OK) {
         err_msg = ssh_get_error(sshc->ssh_session);
         failf(data, "%s", err_msg);
-        MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+        rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED);
         break;
       }
 
@@ -1872,12 +2251,7 @@
          figure out a "real" bitmask */
       sshc->orig_waitfor = data->req.keepon;
 
-      /* we want to use the _sending_ function even when the socket turns
-         out readable as the underlying libssh scp send function will deal
-         with both accordingly */
-      data->state.select_bits = CURL_CSELECT_OUT;
-
-      myssh_state(data, sshc, SSH_STOP);
+      myssh_to(data, sshc, SSH_STOP);
 
       break;
 
@@ -1887,20 +2261,20 @@
       if(rc != SSH_OK) {
         err_msg = ssh_get_error(sshc->ssh_session);
         failf(data, "%s", err_msg);
-        MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
+        rc = myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT);
         break;
       }
-      myssh_state(data, sshc, SSH_SCP_DOWNLOAD);
+      myssh_to(data, sshc, SSH_SCP_DOWNLOAD);
       FALLTHROUGH();
 
-    case SSH_SCP_DOWNLOAD:{
+    case SSH_SCP_DOWNLOAD: {
         curl_off_t bytecount;
 
         rc = ssh_scp_pull_request(sshc->scp_session);
         if(rc != SSH_SCP_REQUEST_NEWFILE) {
           err_msg = ssh_get_error(sshc->ssh_session);
           failf(data, "%s", err_msg);
-          MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
+          rc = myssh_to_ERROR(data, sshc, CURLE_REMOTE_FILE_NOT_FOUND);
           break;
         }
 
@@ -1912,19 +2286,14 @@
         /* not set by Curl_xfer_setup to preserve keepon bits */
         conn->writesockfd = conn->sockfd;
 
-        /* we want to use the _receiving_ function even when the socket turns
-           out writableable as the underlying libssh recv function will deal
-           with both accordingly */
-        data->state.select_bits = CURL_CSELECT_IN;
-
-        myssh_state(data, sshc, SSH_STOP);
+        myssh_to(data, sshc, SSH_STOP);
         break;
-      }
+    }
     case SSH_SCP_DONE:
       if(data->state.upload)
-        myssh_state(data, sshc, SSH_SCP_SEND_EOF);
+        myssh_to(data, sshc, SSH_SCP_SEND_EOF);
       else
-        myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
+        myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE);
       break;
 
     case SSH_SCP_SEND_EOF:
@@ -1942,7 +2311,7 @@
         }
       }
 
-      myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE);
+      myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE);
       break;
 
     case SSH_SCP_CHANNEL_FREE:
@@ -1954,7 +2323,7 @@
 
       ssh_set_blocking(sshc->ssh_session, 0);
 
-      myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
+      myssh_to(data, sshc, SSH_SESSION_DISCONNECT);
       FALLTHROUGH();
 
     case SSH_SESSION_DISCONNECT:
@@ -1985,7 +2354,7 @@
 
       SSH_STRING_FREE_CHAR(sshc->homedir);
 
-      myssh_state(data, sshc, SSH_SESSION_FREE);
+      myssh_to(data, sshc, SSH_SESSION_FREE);
       FALLTHROUGH();
     case SSH_SESSION_FREE:
       sshc_cleanup(sshc);
@@ -1995,14 +2364,14 @@
       connclose(conn, "SSH session free");
       sshc->state = SSH_SESSION_FREE;   /* current */
       sshc->nextstate = SSH_NO_STATE;
-      myssh_state(data, sshc, SSH_STOP);
+      myssh_to(data, sshc, SSH_STOP);
       break;
 
     case SSH_QUIT:
     default:
       /* internal error */
       sshc->nextstate = SSH_NO_STATE;
-      myssh_state(data, sshc, SSH_STOP);
+      myssh_to(data, sshc, SSH_STOP);
       break;
 
     }
@@ -2014,7 +2383,9 @@
        right direction too)! */
     *block = TRUE;
   }
-
+  if(!result && (sshc->state == SSH_STOP))
+    result = sshc->actualcode;
+  DEBUGF(infof(data, "SSH: myssh_statemach_act -> %d", result));
   return result;
 }
 
@@ -2284,7 +2655,7 @@
   /* we do not verify here, we do it at the state machine,
    * after connection */
 
-  myssh_state(data, sshc, SSH_INIT);
+  myssh_to(data, sshc, SSH_INIT);
 
   result = myssh_multi_statemach(data, done);
 
@@ -2327,7 +2698,7 @@
     return CURLE_FAILED_INIT;
 
   /* start the first command in the DO phase */
-  myssh_state(data, sshc, SSH_SCP_TRANS_INIT);
+  myssh_to(data, sshc, SSH_SCP_TRANS_INIT);
 
   result = myssh_multi_statemach(data, dophase_done);
 
@@ -2441,7 +2812,7 @@
   if(sshc && sshc->ssh_session && sshp) {
     /* only if there is a session still around to use! */
 
-    myssh_state(data, sshc, SSH_SESSION_DISCONNECT);
+    myssh_to(data, sshc, SSH_SESSION_DISCONNECT);
 
     result = myssh_block_statemach(data, sshc, sshp, TRUE);
   }
@@ -2482,24 +2853,25 @@
   if(!sshc)
     return CURLE_FAILED_INIT;
   if(!status)
-    myssh_state(data, sshc, SSH_SCP_DONE);
+    myssh_to(data, sshc, SSH_SCP_DONE);
 
   return myssh_done(data, sshc, status);
 }
 
-static ssize_t scp_send(struct Curl_easy *data, int sockindex,
-                        const void *mem, size_t len, bool eos, CURLcode *err)
+static CURLcode scp_send(struct Curl_easy *data, int sockindex,
+                         const void *mem, size_t len, bool eos,
+                         size_t *pnwritten)
 {
   int rc;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+
   (void) sockindex; /* we only support SCP on the fixed known primary socket */
   (void)eos;
+  *pnwritten = 0;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  if(!sshc)
+    return CURLE_FAILED_INIT;
 
   rc = ssh_scp_write(sshc->scp_session, mem, len);
 
@@ -2509,32 +2881,30 @@
    * Currently rc can only be number of bytes read or SSH_ERROR. */
   myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN));
 
-  if(rc == SSH_AGAIN) {
-    *err = CURLE_AGAIN;
-    return 0;
-  }
+  if(rc == SSH_AGAIN)
+    return CURLE_AGAIN;
   else
 #endif
-  if(rc != SSH_OK) {
-    *err = CURLE_SSH;
-    return -1;
-  }
+  if(rc != SSH_OK)
+    return CURLE_SSH;
 
-  return len;
+  *pnwritten = len;
+  return CURLE_OK;
 }
 
-static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
-                        char *mem, size_t len, CURLcode *err)
+static CURLcode scp_recv(struct Curl_easy *data, int sockindex,
+                         char *mem, size_t len, size_t *pnread)
 {
-  ssize_t nread;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
-  (void) sockindex; /* we only support SCP on the fixed known primary socket */
+  ssize_t nread;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  (void) sockindex; /* we only support SCP on the fixed known primary socket */
+  *pnread = 0;
+
+  if(!sshc)
+    return CURLE_FAILED_INIT;
+
   /* libssh returns int */
   nread = ssh_scp_read(sshc->scp_session, mem, len);
 
@@ -2544,13 +2914,11 @@
    * Currently rc can only be SSH_OK or SSH_ERROR. */
 
   myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN));
-  if(nread == SSH_AGAIN) {
-    *err = CURLE_AGAIN;
-    nread = -1;
-  }
+  if(nread == SSH_AGAIN)
+    return CURLE_AGAIN;
 #endif
-
-  return nread;
+  *pnread = (size_t)nread;
+  return CURLE_OK;
 }
 
 /*
@@ -2581,7 +2949,7 @@
     return CURLE_FAILED_INIT;
 
   /* start the first command in the DO phase */
-  myssh_state(data, sshc, SSH_SFTP_QUOTE_INIT);
+  myssh_to(data, sshc, SSH_SFTP_QUOTE_INIT);
 
   /* run the state-machine */
   result = myssh_multi_statemach(data, dophase_done);
@@ -2622,7 +2990,7 @@
 
   if(sshc && sshc->ssh_session && sshp) {
     /* only if there is a session still around to use! */
-    myssh_state(data, sshc, SSH_SFTP_SHUTDOWN);
+    myssh_to(data, sshc, SSH_SFTP_SHUTDOWN);
     result = myssh_block_statemach(data, sshc, sshp, TRUE);
   }
 
@@ -2644,26 +3012,27 @@
        operation */
     if(!premature && data->set.postquote && !conn->bits.retry)
       sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
-    myssh_state(data, sshc, SSH_SFTP_CLOSE);
+    myssh_to(data, sshc, SSH_SFTP_CLOSE);
   }
   return myssh_done(data, sshc, status);
 }
 
 /* return number of sent bytes */
-static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
-                         const void *mem, size_t len, bool eos,
-                         CURLcode *err)
+static CURLcode sftp_send(struct Curl_easy *data, int sockindex,
+                          const void *mem, size_t len, bool eos,
+                          size_t *pnwritten)
 {
-  ssize_t nwrite;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+  ssize_t nwrite;
+
   (void)sockindex;
   (void)eos;
+  *pnwritten = 0;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  if(!sshc)
+    return CURLE_FAILED_INIT;
+
   /* limit the writes to the maximum specified in Section 3 of
    * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
    */
@@ -2675,31 +3044,27 @@
       sftp_file_set_nonblocking(sshc->sftp_file);
       if(sftp_aio_begin_write(sshc->sftp_file, mem, len,
                               &sshc->sftp_aio) == SSH_ERROR) {
-        *err = CURLE_SEND_ERROR;
-        return -1;
+        return CURLE_SEND_ERROR;
       }
       sshc->sftp_send_state = 1;
       FALLTHROUGH();
     case 1:
       nwrite = sftp_aio_wait_write(&sshc->sftp_aio);
       myssh_block2waitfor(conn, sshc, (nwrite == SSH_AGAIN) ? TRUE : FALSE);
-      if(nwrite == SSH_AGAIN) {
-        *err = CURLE_AGAIN;
-        return 0;
-      }
-      else if(nwrite < 0) {
-        *err = CURLE_SEND_ERROR;
-        return -1;
-      }
+      if(nwrite == SSH_AGAIN)
+        return CURLE_AGAIN;
+      else if(nwrite < 0)
+        return CURLE_SEND_ERROR;
       if(sshc->sftp_aio) {
         sftp_aio_free(sshc->sftp_aio);
         sshc->sftp_aio = NULL;
       }
       sshc->sftp_send_state = 0;
-      return nwrite;
+      *pnwritten = (size_t)nwrite;
+      return CURLE_OK;
     default:
       /* we never reach here */
-      return -1;
+      return CURLE_SEND_ERROR;
   }
 #else
   nwrite = sftp_write(sshc->sftp_file, mem, len);
@@ -2713,12 +3078,11 @@
   }
   else
 #endif
-  if(nwrite < 0) {
-    *err = CURLE_SSH;
-    nwrite = -1;
-  }
+  if(nwrite < 0)
+    return CURLE_SSH;
 
-  return nwrite;
+  *pnwritten = (size_t)nwrite;
+  return CURLE_OK;
 #endif
 }
 
@@ -2726,28 +3090,26 @@
  * Return number of received (decrypted) bytes
  * or <0 on error
  */
-static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
-                         char *mem, size_t len, CURLcode *err)
+static CURLcode sftp_recv(struct Curl_easy *data, int sockindex,
+                          char *mem, size_t len, size_t *pnread)
 {
-  ssize_t nread;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+  ssize_t nread;
+
   (void)sockindex;
+  *pnread = 0;
 
   DEBUGASSERT(len < CURL_MAX_READ_SIZE);
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  if(!sshc)
+    return CURLE_FAILED_INIT;
 
   switch(sshc->sftp_recv_state) {
     case 0:
       sshc->sftp_file_index =
         sftp_async_read_begin(sshc->sftp_file, (uint32_t)len);
-      if(sshc->sftp_file_index < 0) {
-        *err = CURLE_RECV_ERROR;
-        return -1;
-      }
+      if(sshc->sftp_file_index < 0)
+        return CURLE_RECV_ERROR;
 
       FALLTHROUGH();
     case 1:
@@ -2757,321 +3119,21 @@
 
       myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN));
 
-      if(nread == SSH_AGAIN) {
-        *err = CURLE_AGAIN;
-        return -1;
-      }
-      else if(nread < 0) {
-        *err = CURLE_RECV_ERROR;
-        return -1;
-      }
+      if(nread == SSH_AGAIN)
+        return CURLE_AGAIN;
+      else if(nread < 0)
+        return CURLE_RECV_ERROR;
 
       sshc->sftp_recv_state = 0;
-      return nread;
+      *pnread = (size_t)nread;
+      return CURLE_OK;
 
     default:
       /* we never reach here */
-      return -1;
+      return CURLE_RECV_ERROR;
   }
 }
 
-static void sftp_quote(struct Curl_easy *data,
-                       struct ssh_conn *sshc,
-                       struct SSHPROTO *sshp)
-{
-  const char *cp;
-  CURLcode result;
-
-  /*
-   * Support some of the "FTP" commands
-   */
-  char *cmd = sshc->quote_item->data;
-  sshc->acceptfail = FALSE;
-
-  /* if a command starts with an asterisk, which a legal SFTP command never
-     can, the command will be allowed to fail without it causing any
-     aborts or cancels etc. It will cause libcurl to act as if the command
-     is successful, whatever the server responds. */
-
-  if(cmd[0] == '*') {
-    cmd++;
-    sshc->acceptfail = TRUE;
-  }
-
-  if(strcasecompare("pwd", cmd)) {
-    /* output debug output if that is requested */
-    char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path);
-    if(!tmp) {
-      sshc->actualcode = CURLE_OUT_OF_MEMORY;
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      return;
-    }
-    Curl_debug(data, CURLINFO_HEADER_OUT, "PWD\n", 4);
-    Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
-
-    /* this sends an FTP-like "header" to the header callback so that the
-       current directory can be read very similar to how it is read when
-       using ordinary FTP. */
-    result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp));
-    free(tmp);
-    if(result) {
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = result;
-    }
-    else
-      myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE);
-    return;
-  }
-
-  /*
-   * the arguments following the command must be separated from the
-   * command with a space so we can check for it unconditionally
-   */
-  cp = strchr(cmd, ' ');
-  if(!cp) {
-    failf(data, "Syntax error in SFTP command. Supply parameter(s)");
-    myssh_state(data, sshc, SSH_SFTP_CLOSE);
-    sshc->nextstate = SSH_NO_STATE;
-    sshc->actualcode = CURLE_QUOTE_ERROR;
-    return;
-  }
-
-  /*
-   * also, every command takes at least one argument so we get that
-   * first argument right now
-   */
-  result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir);
-  if(result) {
-    if(result == CURLE_OUT_OF_MEMORY)
-      failf(data, "Out of memory");
-    else
-      failf(data, "Syntax error: Bad first parameter");
-    myssh_state(data, sshc, SSH_SFTP_CLOSE);
-    sshc->nextstate = SSH_NO_STATE;
-    sshc->actualcode = result;
-    return;
-  }
-
-  /*
-   * SFTP is a binary protocol, so we do not send text commands
-   * to the server. Instead, we scan for commands used by
-   * OpenSSH's sftp program and call the appropriate libssh
-   * functions.
-   */
-  if(!strncmp(cmd, "chgrp ", 6) ||
-     !strncmp(cmd, "chmod ", 6) ||
-     !strncmp(cmd, "chown ", 6) ||
-     !strncmp(cmd, "atime ", 6) ||
-     !strncmp(cmd, "mtime ", 6)) {
-    /* attribute change */
-
-    /* sshc->quote_path1 contains the mode to set */
-    /* get the destination */
-    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
-    if(result) {
-      if(result == CURLE_OUT_OF_MEMORY)
-        failf(data, "Out of memory");
-      else
-        failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: "
-              "Bad second parameter");
-      Curl_safefree(sshc->quote_path1);
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = result;
-      return;
-    }
-    sshc->quote_attrs = NULL;
-    myssh_state(data, sshc, SSH_SFTP_QUOTE_STAT);
-    return;
-  }
-  if(!strncmp(cmd, "ln ", 3) ||
-     !strncmp(cmd, "symlink ", 8)) {
-    /* symbolic linking */
-    /* sshc->quote_path1 is the source */
-    /* get the destination */
-    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
-    if(result) {
-      if(result == CURLE_OUT_OF_MEMORY)
-        failf(data, "Out of memory");
-      else
-        failf(data, "Syntax error in ln/symlink: Bad second parameter");
-      Curl_safefree(sshc->quote_path1);
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = result;
-      return;
-    }
-    myssh_state(data, sshc, SSH_SFTP_QUOTE_SYMLINK);
-    return;
-  }
-  else if(!strncmp(cmd, "mkdir ", 6)) {
-    /* create dir */
-    myssh_state(data, sshc, SSH_SFTP_QUOTE_MKDIR);
-    return;
-  }
-  else if(!strncmp(cmd, "rename ", 7)) {
-    /* rename file */
-    /* first param is the source path */
-    /* second param is the dest. path */
-    result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir);
-    if(result) {
-      if(result == CURLE_OUT_OF_MEMORY)
-        failf(data, "Out of memory");
-      else
-        failf(data, "Syntax error in rename: Bad second parameter");
-      Curl_safefree(sshc->quote_path1);
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = result;
-      return;
-    }
-    myssh_state(data, sshc, SSH_SFTP_QUOTE_RENAME);
-    return;
-  }
-  else if(!strncmp(cmd, "rmdir ", 6)) {
-    /* delete dir */
-    myssh_state(data, sshc, SSH_SFTP_QUOTE_RMDIR);
-    return;
-  }
-  else if(!strncmp(cmd, "rm ", 3)) {
-    myssh_state(data, sshc, SSH_SFTP_QUOTE_UNLINK);
-    return;
-  }
-#ifdef HAS_STATVFS_SUPPORT
-  else if(!strncmp(cmd, "statvfs ", 8)) {
-    myssh_state(data, sshc, SSH_SFTP_QUOTE_STATVFS);
-    return;
-  }
-#endif
-
-  failf(data, "Unknown SFTP command");
-  Curl_safefree(sshc->quote_path1);
-  Curl_safefree(sshc->quote_path2);
-  myssh_state(data, sshc, SSH_SFTP_CLOSE);
-  sshc->nextstate = SSH_NO_STATE;
-  sshc->actualcode = CURLE_QUOTE_ERROR;
-}
-
-static void sftp_quote_stat(struct Curl_easy *data,
-                            struct ssh_conn *sshc)
-{
-  char *cmd = sshc->quote_item->data;
-  sshc->acceptfail = FALSE;
-
-  /* if a command starts with an asterisk, which a legal SFTP command never
-     can, the command will be allowed to fail without it causing any
-     aborts or cancels etc. It will cause libcurl to act as if the command
-     is successful, whatever the server responds. */
-
-  if(cmd[0] == '*') {
-    cmd++;
-    sshc->acceptfail = TRUE;
-  }
-
-  /* We read the file attributes, store them in sshc->quote_attrs
-   * and modify them accordingly to command. Then we switch to
-   * QUOTE_SETSTAT state to write new ones.
-   */
-
-  if(sshc->quote_attrs)
-    sftp_attributes_free(sshc->quote_attrs);
-  sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
-  if(!sshc->quote_attrs) {
-    Curl_safefree(sshc->quote_path1);
-    Curl_safefree(sshc->quote_path2);
-    failf(data, "Attempt to get SFTP stats failed: %d",
-          sftp_get_error(sshc->sftp_session));
-    myssh_state(data, sshc, SSH_SFTP_CLOSE);
-    sshc->nextstate = SSH_NO_STATE;
-    sshc->actualcode = CURLE_QUOTE_ERROR;
-    return;
-  }
-
-  /* Now set the new attributes... */
-  if(!strncmp(cmd, "chgrp", 5)) {
-    const char *p = sshc->quote_path1;
-    curl_off_t gid;
-    (void)curlx_str_number(&p, &gid, UINT_MAX);
-    sshc->quote_attrs->gid = (uint32_t)gid;
-    if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
-       !sshc->acceptfail) {
-      Curl_safefree(sshc->quote_path1);
-      Curl_safefree(sshc->quote_path2);
-      failf(data, "Syntax error: chgrp gid not a number");
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = CURLE_QUOTE_ERROR;
-      return;
-    }
-    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
-  }
-  else if(!strncmp(cmd, "chmod", 5)) {
-    curl_off_t perms;
-    const char *p = sshc->quote_path1;
-    if(curlx_str_octal(&p, &perms, 07777)) {
-      Curl_safefree(sshc->quote_path1);
-      Curl_safefree(sshc->quote_path2);
-      failf(data, "Syntax error: chmod permissions not a number");
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = CURLE_QUOTE_ERROR;
-      return;
-    }
-    sshc->quote_attrs->permissions = (mode_t)perms;
-    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
-  }
-  else if(!strncmp(cmd, "chown", 5)) {
-    const char *p = sshc->quote_path1;
-    curl_off_t uid;
-    (void)curlx_str_number(&p, &uid, UINT_MAX);
-    if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
-       !sshc->acceptfail) {
-      Curl_safefree(sshc->quote_path1);
-      Curl_safefree(sshc->quote_path2);
-      failf(data, "Syntax error: chown uid not a number");
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = CURLE_QUOTE_ERROR;
-      return;
-    }
-    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
-  }
-  else if(!strncmp(cmd, "atime", 5) ||
-          !strncmp(cmd, "mtime", 5)) {
-    time_t date = Curl_getdate_capped(sshc->quote_path1);
-    bool fail = FALSE;
-    if(date == -1) {
-      failf(data, "incorrect date format for %.*s", 5, cmd);
-      fail = TRUE;
-    }
-#if SIZEOF_TIME_T > 4
-    else if(date > 0xffffffff) {
-      failf(data, "date overflow");
-      fail = TRUE; /* avoid setting a capped time */
-    }
-#endif
-    if(fail) {
-      Curl_safefree(sshc->quote_path1);
-      Curl_safefree(sshc->quote_path2);
-      myssh_state(data, sshc, SSH_SFTP_CLOSE);
-      sshc->nextstate = SSH_NO_STATE;
-      sshc->actualcode = CURLE_QUOTE_ERROR;
-      return;
-    }
-    if(!strncmp(cmd, "atime", 5))
-      sshc->quote_attrs->atime = (uint32_t)date;
-    else /* mtime */
-      sshc->quote_attrs->mtime = (uint32_t)date;
-
-    sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME;
-  }
-
-  /* Now send the completed structure... */
-  myssh_state(data, sshc, SSH_SFTP_QUOTE_SETSTAT);
-  return;
-}
 
 CURLcode Curl_ssh_init(void)
 {
diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index c16b3ac..d599d3c 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/vssh/libssh2.c
@@ -61,11 +61,9 @@
 #include "../speedcheck.h"
 #include "../getinfo.h"
 #include "../strdup.h"
-#include "../strcase.h"
 #include "../vtls/vtls.h"
 #include "../cfilters.h"
 #include "../connect.h"
-#include "../inet_ntop.h"
 #include "../parsedate.h" /* for the week day and month names */
 #include "../sockaddr.h" /* required for Curl_sockaddr_storage */
 #include "../multiif.h"
@@ -696,7 +694,7 @@
 
     /* This does NOT verify the length of 'pubkey_md5' separately, which will
        make the comparison below fail unless it is exactly 32 characters */
-    if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
+    if(!fingerprint || !curl_strequal(md5buffer, pubkey_md5)) {
       if(fingerprint) {
         failf(data,
               "Denied establishing ssh session: mismatch md5 fingerprint. "
@@ -920,7 +918,7 @@
     sshc->acceptfail = TRUE;
   }
 
-  if(strcasecompare("pwd", cmd)) {
+  if(curl_strequal("pwd", cmd)) {
     /* output debug output if that is requested */
     char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path);
     if(!tmp)
@@ -1210,15 +1208,9 @@
      figure out a "real" bitmask */
   sshc->orig_waitfor = data->req.keepon;
 
-  /* we want to use the _sending_ function even when the socket turns
-     out readable as the underlying libssh2 sftp send function will deal
-     with both accordingly */
-  data->state.select_bits = CURL_CSELECT_OUT;
-
   /* since we do not really wait for anything at this point, we want the
-     state machine to move on as soon as possible so we set a very short
-     timeout here */
-  Curl_expire(data, 0, EXPIRE_RUN_NOW);
+     state machine to move on as soon as possible so mark this as dirty */
+  Curl_multi_mark_dirty(data);
 
   myssh_state(data, sshc, SSH_STOP);
   return CURLE_OK;
@@ -1553,10 +1545,6 @@
   /* not set by Curl_xfer_setup to preserve keepon bits */
   data->conn->writesockfd = data->conn->sockfd;
 
-  /* we want to use the _receiving_ function even when the socket turns
-     out writableable as the underlying libssh2 recv function will deal
-     with both accordingly */
-  data->state.select_bits = CURL_CSELECT_IN;
   myssh_state(data, sshc, SSH_STOP);
 
   return CURLE_OK;
@@ -1809,7 +1797,7 @@
 }
 
 static CURLcode ssh_state_auth_agent_init(struct Curl_easy *data,
-                                     struct ssh_conn *sshc)
+                                          struct ssh_conn *sshc)
 {
   int rc = 0;
   if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT)
@@ -1918,7 +1906,7 @@
 }
 
 static CURLcode ssh_state_auth_key(struct Curl_easy *data,
-                              struct ssh_conn *sshc)
+                                   struct ssh_conn *sshc)
 {
   /* Authentication failed. Continue with keyboard-interactive now. */
   struct connectdata *conn = data->conn;
@@ -2274,7 +2262,7 @@
 }
 
 static CURLcode ssh_state_sftp_quote_statvfs(struct Curl_easy *data,
-                                        struct ssh_conn *sshc)
+                                             struct ssh_conn *sshc)
 {
   LIBSSH2_SFTP_STATVFS statvfs;
   int rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1,
@@ -2477,11 +2465,6 @@
   /* not set by Curl_xfer_setup to preserve keepon bits */
   data->conn->writesockfd = data->conn->sockfd;
 
-  /* we want to use the _receiving_ function even when the socket turns
-     out writableable as the underlying libssh2 recv function will deal
-     with both accordingly */
-  data->state.select_bits = CURL_CSELECT_IN;
-
   myssh_state(data, sshc, SSH_STOP);
   return CURLE_OK;
 }
@@ -2524,7 +2507,7 @@
 }
 
 static CURLcode ssh_state_sftp_shutdown(struct Curl_easy *data,
-                                   struct ssh_conn *sshc)
+                                        struct ssh_conn *sshc)
 {
   /* during times we get here due to a broken transfer and then the
      sftp_handle might not have been taken down so make sure that is done
@@ -2635,11 +2618,6 @@
      figure out a "real" bitmask */
   sshc->orig_waitfor = data->req.keepon;
 
-  /* we want to use the _sending_ function even when the socket turns
-     out readable as the underlying libssh2 scp send function will deal
-     with both accordingly */
-  data->state.select_bits = CURL_CSELECT_OUT;
-
   myssh_state(data, sshc, SSH_STOP);
 
   return CURLE_OK;
@@ -3267,7 +3245,6 @@
   if(!sshc)
     return CURLE_OUT_OF_MEMORY;
 
-  sshc->initialised = TRUE;
   if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, myssh_conn_dtor))
     return CURLE_OUT_OF_MEMORY;
 
@@ -3291,7 +3268,7 @@
                             size_t length, int flags, void **abstract)
 {
   struct Curl_easy *data = (struct Curl_easy *)*abstract;
-  ssize_t nread;
+  size_t nread;
   CURLcode result;
   struct connectdata *conn = data->conn;
   Curl_recv *backup = conn->recv[0];
@@ -3312,7 +3289,7 @@
   else if(result)
     return -1; /* generic error */
   Curl_debug(data, CURLINFO_DATA_IN, (const char *)buffer, (size_t)nread);
-  return nread;
+  return (ssize_t)nread;
 }
 
 static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer,
@@ -3611,101 +3588,99 @@
 {
   int rc;
 
-  if(sshc->initialised) {
-    if(sshc->kh) {
-      libssh2_knownhost_free(sshc->kh);
-      sshc->kh = NULL;
-    }
-
-    if(sshc->ssh_agent) {
-      rc = libssh2_agent_disconnect(sshc->ssh_agent);
-      if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
-        return CURLE_AGAIN;
-
-      if((rc < 0) && data) {
-        char *err_msg = NULL;
-        (void)libssh2_session_last_error(sshc->ssh_session,
-                                         &err_msg, NULL, 0);
-        infof(data, "Failed to disconnect from libssh2 agent: %d %s",
-              rc, err_msg);
-      }
-      libssh2_agent_free(sshc->ssh_agent);
-      sshc->ssh_agent = NULL;
-
-      /* NB: there is no need to free identities, they are part of internal
-         agent stuff */
-      sshc->sshagent_identity = NULL;
-      sshc->sshagent_prev_identity = NULL;
-    }
-
-    if(sshc->sftp_handle) {
-      rc = libssh2_sftp_close(sshc->sftp_handle);
-      if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
-        return CURLE_AGAIN;
-
-      if((rc < 0) && data) {
-        char *err_msg = NULL;
-        (void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
-                                         NULL, 0);
-        infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
-      }
-      sshc->sftp_handle = NULL;
-    }
-
-    if(sshc->ssh_channel) {
-      rc = libssh2_channel_free(sshc->ssh_channel);
-      if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
-        return CURLE_AGAIN;
-
-      if((rc < 0) && data) {
-        char *err_msg = NULL;
-        (void)libssh2_session_last_error(sshc->ssh_session,
-                                         &err_msg, NULL, 0);
-        infof(data, "Failed to free libssh2 scp subsystem: %d %s",
-              rc, err_msg);
-      }
-      sshc->ssh_channel = NULL;
-    }
-
-    if(sshc->sftp_session) {
-      rc = libssh2_sftp_shutdown(sshc->sftp_session);
-      if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
-        return CURLE_AGAIN;
-
-      if((rc < 0) && data)
-        infof(data, "Failed to stop libssh2 sftp subsystem");
-      sshc->sftp_session = NULL;
-    }
-
-    if(sshc->ssh_session) {
-      rc = libssh2_session_free(sshc->ssh_session);
-      if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
-        return CURLE_AGAIN;
-
-      if((rc < 0) && data) {
-        char *err_msg = NULL;
-        (void)libssh2_session_last_error(sshc->ssh_session,
-                                         &err_msg, NULL, 0);
-        infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
-      }
-      sshc->ssh_session = NULL;
-    }
-
-    /* worst-case scenario cleanup */
-    DEBUGASSERT(sshc->ssh_session == NULL);
-    DEBUGASSERT(sshc->ssh_channel == NULL);
-    DEBUGASSERT(sshc->sftp_session == NULL);
-    DEBUGASSERT(sshc->sftp_handle == NULL);
-    DEBUGASSERT(sshc->kh == NULL);
-    DEBUGASSERT(sshc->ssh_agent == NULL);
-
-    Curl_safefree(sshc->rsa_pub);
-    Curl_safefree(sshc->rsa);
-    Curl_safefree(sshc->quote_path1);
-    Curl_safefree(sshc->quote_path2);
-    Curl_safefree(sshc->homedir);
-    sshc->initialised = FALSE;
+  if(sshc->kh) {
+    libssh2_knownhost_free(sshc->kh);
+    sshc->kh = NULL;
   }
+
+  if(sshc->ssh_agent) {
+    rc = libssh2_agent_disconnect(sshc->ssh_agent);
+    if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
+      return CURLE_AGAIN;
+
+    if((rc < 0) && data) {
+      char *err_msg = NULL;
+      (void)libssh2_session_last_error(sshc->ssh_session,
+                                       &err_msg, NULL, 0);
+      infof(data, "Failed to disconnect from libssh2 agent: %d %s",
+            rc, err_msg);
+    }
+    libssh2_agent_free(sshc->ssh_agent);
+    sshc->ssh_agent = NULL;
+
+    /* NB: there is no need to free identities, they are part of internal
+       agent stuff */
+    sshc->sshagent_identity = NULL;
+    sshc->sshagent_prev_identity = NULL;
+  }
+
+  if(sshc->sftp_handle) {
+    rc = libssh2_sftp_close(sshc->sftp_handle);
+    if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
+      return CURLE_AGAIN;
+
+    if((rc < 0) && data) {
+      char *err_msg = NULL;
+      (void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
+                                       NULL, 0);
+      infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
+    }
+    sshc->sftp_handle = NULL;
+  }
+
+  if(sshc->ssh_channel) {
+    rc = libssh2_channel_free(sshc->ssh_channel);
+    if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
+      return CURLE_AGAIN;
+
+    if((rc < 0) && data) {
+      char *err_msg = NULL;
+      (void)libssh2_session_last_error(sshc->ssh_session,
+                                       &err_msg, NULL, 0);
+      infof(data, "Failed to free libssh2 scp subsystem: %d %s",
+            rc, err_msg);
+    }
+    sshc->ssh_channel = NULL;
+  }
+
+  if(sshc->sftp_session) {
+    rc = libssh2_sftp_shutdown(sshc->sftp_session);
+    if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
+      return CURLE_AGAIN;
+
+    if((rc < 0) && data)
+      infof(data, "Failed to stop libssh2 sftp subsystem");
+    sshc->sftp_session = NULL;
+  }
+
+  if(sshc->ssh_session) {
+    rc = libssh2_session_free(sshc->ssh_session);
+    if(!block && (rc == LIBSSH2_ERROR_EAGAIN))
+      return CURLE_AGAIN;
+
+    if((rc < 0) && data) {
+      char *err_msg = NULL;
+      (void)libssh2_session_last_error(sshc->ssh_session,
+                                       &err_msg, NULL, 0);
+      infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
+    }
+    sshc->ssh_session = NULL;
+  }
+
+  /* worst-case scenario cleanup */
+  DEBUGASSERT(sshc->ssh_session == NULL);
+  DEBUGASSERT(sshc->ssh_channel == NULL);
+  DEBUGASSERT(sshc->sftp_session == NULL);
+  DEBUGASSERT(sshc->sftp_handle == NULL);
+  DEBUGASSERT(sshc->kh == NULL);
+  DEBUGASSERT(sshc->ssh_agent == NULL);
+
+  Curl_safefree(sshc->rsa_pub);
+  Curl_safefree(sshc->rsa);
+  Curl_safefree(sshc->quote_path1);
+  Curl_safefree(sshc->quote_path2);
+  Curl_safefree(sshc->homedir);
+
   return CURLE_OK;
 }
 
@@ -3770,58 +3745,63 @@
   return ssh_done(data, status);
 }
 
-static ssize_t scp_send(struct Curl_easy *data, int sockindex,
-                        const void *mem, size_t len, bool eos, CURLcode *err)
+static CURLcode scp_send(struct Curl_easy *data, int sockindex,
+                         const void *mem, size_t len, bool eos,
+                         size_t *pnwritten)
 {
-  ssize_t nwrite;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+  CURLcode result = CURLE_OK;
+  ssize_t nwritten;
+
   (void)sockindex; /* we only support SCP on the fixed known primary socket */
   (void)eos;
+  *pnwritten = 0;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  if(!sshc)
+    return CURLE_FAILED_INIT;
+
   /* libssh2_channel_write() returns int! */
-  nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
+  nwritten = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
 
-  ssh_block2waitfor(data, sshc, (nwrite == LIBSSH2_ERROR_EAGAIN));
+  ssh_block2waitfor(data, sshc, (nwritten == LIBSSH2_ERROR_EAGAIN));
 
-  if(nwrite == LIBSSH2_ERROR_EAGAIN) {
-    *err = CURLE_AGAIN;
-    nwrite = 0;
-  }
-  else if(nwrite < LIBSSH2_ERROR_NONE) {
-    *err = libssh2_session_error_to_CURLE((int)nwrite);
-    nwrite = -1;
-  }
+  if(nwritten == LIBSSH2_ERROR_EAGAIN)
+    result = CURLE_AGAIN;
+  else if(nwritten < LIBSSH2_ERROR_NONE)
+    result = libssh2_session_error_to_CURLE((int)nwritten);
+  else
+    *pnwritten = (size_t)nwritten;
 
-  return nwrite;
+  return result;
 }
 
-static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
-                        char *mem, size_t len, CURLcode *err)
+static CURLcode scp_recv(struct Curl_easy *data, int sockindex,
+                         char *mem, size_t len, size_t *pnread)
 {
-  ssize_t nread;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
-  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+  CURLcode result = CURLE_OK;
+  ssize_t nread;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+  *pnread = 0;
+
+  if(!sshc)
+    return CURLE_FAILED_INIT;
+
   /* libssh2_channel_read() returns int */
   nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len);
 
   ssh_block2waitfor(data, sshc, (nread == LIBSSH2_ERROR_EAGAIN));
-  if(nread == LIBSSH2_ERROR_EAGAIN) {
-    *err = CURLE_AGAIN;
-    nread = -1;
-  }
+  if(nread == LIBSSH2_ERROR_EAGAIN)
+    return CURLE_AGAIN;
+  else if(nread < LIBSSH2_ERROR_NONE)
+    result = libssh2_session_error_to_CURLE((int)nread);
+  else
+    *pnread = (size_t)nread;
 
-  return nread;
+  return result;
 }
 
 /*
@@ -3906,7 +3886,7 @@
 }
 
 static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
-                               bool premature)
+                          bool premature)
 {
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
@@ -3926,64 +3906,61 @@
 }
 
 /* return number of sent bytes */
-static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
-                         const void *mem, size_t len, bool eos, CURLcode *err)
+static CURLcode sftp_send(struct Curl_easy *data, int sockindex,
+                          const void *mem, size_t len, bool eos,
+                          size_t *pnwritten)
 {
-  ssize_t nwrite;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
+  ssize_t nwrite;
+
   (void)sockindex;
   (void)eos;
+  *pnwritten = 0;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  if(!sshc)
+    return CURLE_FAILED_INIT;
+
   nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
 
   ssh_block2waitfor(data, sshc, (nwrite == LIBSSH2_ERROR_EAGAIN));
 
-  if(nwrite == LIBSSH2_ERROR_EAGAIN) {
-    *err = CURLE_AGAIN;
-    nwrite = 0;
-  }
-  else if(nwrite < LIBSSH2_ERROR_NONE) {
-    *err = libssh2_session_error_to_CURLE((int)nwrite);
-    nwrite = -1;
-  }
-
-  return nwrite;
+  if(nwrite == LIBSSH2_ERROR_EAGAIN)
+    return CURLE_AGAIN;
+  else if(nwrite < LIBSSH2_ERROR_NONE)
+    return libssh2_session_error_to_CURLE((int)nwrite);
+  *pnwritten = (size_t)nwrite;
+  return CURLE_OK;
 }
 
 /*
  * Return number of received (decrypted) bytes
  * or <0 on error
  */
-static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
-                         char *mem, size_t len, CURLcode *err)
+static CURLcode sftp_recv(struct Curl_easy *data, int sockindex,
+                          char *mem, size_t len, size_t *pnread)
 {
-  ssize_t nread;
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
-  (void)sockindex;
+  ssize_t nread;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  (void)sockindex;
+  *pnread = 0;
+
+  if(!sshc)
+    return CURLE_FAILED_INIT;
+
   nread = libssh2_sftp_read(sshc->sftp_handle, mem, len);
 
   ssh_block2waitfor(data, sshc, (nread == LIBSSH2_ERROR_EAGAIN));
 
-  if(nread == LIBSSH2_ERROR_EAGAIN) {
-    *err = CURLE_AGAIN;
-    nread = -1;
+  if(nread == LIBSSH2_ERROR_EAGAIN)
+    return CURLE_AGAIN;
+  else if(nread < 0)
+    return libssh2_session_error_to_CURLE((int)nread);
 
-  }
-  else if(nread < 0) {
-    *err = libssh2_session_error_to_CURLE((int)nread);
-  }
-  return nread;
+  *pnread = (size_t)nread;
+  return CURLE_OK;
 }
 
 static const char *sftp_libssh2_strerror(unsigned long err)
diff --git a/Utilities/cmcurl/lib/vssh/ssh.h b/Utilities/cmcurl/lib/vssh/ssh.h
index feee886..4056c39 100644
--- a/Utilities/cmcurl/lib/vssh/ssh.h
+++ b/Utilities/cmcurl/lib/vssh/ssh.h
@@ -191,6 +191,7 @@
   const char *readdir_filename; /* points within readdir_attrs */
   const char *readdir_longentry;
   char *readdir_tmp;
+  BIT(initialised);
 #elif defined(USE_LIBSSH2)
   LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
   LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
@@ -214,8 +215,8 @@
   word32 handleSz;
   byte handle[WOLFSSH_MAX_HANDLE];
   curl_off_t offset;
-#endif /* USE_LIBSSH */
   BIT(initialised);
+#endif /* USE_LIBSSH */
   BIT(authed);                /* the connection has been authenticated fine */
   BIT(acceptfail);            /* used by the SFTP_QUOTE (continue if
                                  quote command fails) */
diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c
index 5097ca0..eed73fd 100644
--- a/Utilities/cmcurl/lib/vssh/wolfssh.c
+++ b/Utilities/cmcurl/lib/vssh/wolfssh.c
@@ -220,37 +220,35 @@
   sshc->state = nowstate;
 }
 
-static ssize_t wscp_send(struct Curl_easy *data, int sockindex,
-                         const void *mem, size_t len, bool eos,
-                         CURLcode *err)
+static CURLcode wscp_send(struct Curl_easy *data, int sockindex,
+                          const void *mem, size_t len, bool eos,
+                          size_t *pnwritten)
 {
-  ssize_t nwrite = 0;
   (void)data;
   (void)sockindex; /* we only support SCP on the fixed known primary socket */
   (void)mem;
   (void)len;
   (void)eos;
-  (void)err;
-
-  return nwrite;
+  *pnwritten = 0;
+  return CURLE_OK;
 }
 
-static ssize_t wscp_recv(struct Curl_easy *data, int sockindex,
-                         char *mem, size_t len, CURLcode *err)
+static CURLcode wscp_recv(struct Curl_easy *data, int sockindex,
+                          char *mem, size_t len, size_t *pnread)
 {
-  ssize_t nread = 0;
   (void)data;
   (void)sockindex; /* we only support SCP on the fixed known primary socket */
   (void)mem;
   (void)len;
-  (void)err;
+  *pnread = 0;
 
-  return nread;
+  return CURLE_OK;
 }
 
 /* return number of sent bytes */
-static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
-                          const void *mem, size_t len, bool eos, CURLcode *err)
+static CURLcode wsftp_send(struct Curl_easy *data, int sockindex,
+                           const void *mem, size_t len, bool eos,
+                           size_t *pnwritten)
 {
   struct connectdata *conn = data->conn;
   struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
@@ -259,10 +257,10 @@
   (void)sockindex;
   (void)eos;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  *pnwritten = 0;
+  if(!sshc)
+    return CURLE_FAILED_INIT;
+
   offset[0] = (word32)sshc->offset & 0xFFFFFFFF;
   offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF;
 
@@ -275,31 +273,30 @@
     rc = wolfSSH_get_error(sshc->ssh_session);
   if(rc == WS_WANT_READ) {
     conn->waitfor = KEEP_RECV;
-    *err = CURLE_AGAIN;
-    return -1;
+    return CURLE_AGAIN;
   }
   else if(rc == WS_WANT_WRITE) {
     conn->waitfor = KEEP_SEND;
-    *err = CURLE_AGAIN;
-    return -1;
+    return CURLE_AGAIN;
   }
   if(rc < 0) {
     failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc);
-    return -1;
+    return CURLE_SEND_ERROR;
   }
   DEBUGASSERT(rc == (int)len);
+  *pnwritten = (size_t)rc;
+  sshc->offset += *pnwritten;
   infof(data, "sent %zu bytes SFTP from offset %" FMT_OFF_T,
-        len, sshc->offset);
-  sshc->offset += len;
-  return (ssize_t)rc;
+        *pnwritten, sshc->offset);
+  return CURLE_OK;
 }
 
 /*
  * Return number of received (decrypted) bytes
  * or <0 on error
  */
-static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex,
-                          char *mem, size_t len, CURLcode *err)
+static CURLcode wsftp_recv(struct Curl_easy *data, int sockindex,
+                           char *mem, size_t len, size_t *pnread)
 {
   int rc;
   struct connectdata *conn = data->conn;
@@ -307,10 +304,10 @@
   word32 offset[2];
   (void)sockindex;
 
-  if(!sshc) {
-    *err = CURLE_FAILED_INIT;
-    return -1;
-  }
+  *pnread = 0;
+  if(!sshc)
+    return CURLE_FAILED_INIT;
+
   offset[0] = (word32)sshc->offset & 0xFFFFFFFF;
   offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF;
 
@@ -322,24 +319,22 @@
     rc = wolfSSH_get_error(sshc->ssh_session);
   if(rc == WS_WANT_READ) {
     conn->waitfor = KEEP_RECV;
-    *err = CURLE_AGAIN;
-    return -1;
+    return CURLE_AGAIN;
   }
   else if(rc == WS_WANT_WRITE) {
     conn->waitfor = KEEP_SEND;
-    *err = CURLE_AGAIN;
-    return -1;
+    return CURLE_AGAIN;
   }
 
   DEBUGASSERT(rc <= (int)len);
 
   if(rc < 0) {
     failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc);
-    return -1;
+    return CURLE_RECV_ERROR;
   }
-  sshc->offset += len;
-
-  return (ssize_t)rc;
+  *pnread = (size_t)rc;
+  sshc->offset += *pnread;
+  return CURLE_OK;
 }
 
 static void wssh_easy_dtor(void *key, size_t klen, void *entry)
@@ -737,15 +732,9 @@
            figure out a "real" bitmask */
         sshc->orig_waitfor = data->req.keepon;
 
-        /* we want to use the _sending_ function even when the socket turns
-           out readable as the underlying libssh2 sftp send function will deal
-           with both accordingly */
-        data->state.select_bits = CURL_CSELECT_OUT;
-
         /* since we do not really wait for anything at this point, we want the
-           state machine to move on as soon as possible so we set a very short
-           timeout here */
-        Curl_expire(data, 0, EXPIRE_RUN_NOW);
+           state machine to move on as soon as possible */
+        Curl_multi_mark_dirty(data);
 
         wssh_state(data, sshc, SSH_STOP);
       }
@@ -833,11 +822,6 @@
       /* not set by Curl_xfer_setup to preserve keepon bits */
       conn->writesockfd = conn->sockfd;
 
-      /* we want to use the _receiving_ function even when the socket turns
-         out writableable as the underlying libssh2 recv function will deal
-         with both accordingly */
-      data->state.select_bits = CURL_CSELECT_IN;
-
       if(result) {
         /* this should never occur; the close state should be entered
            at the time the error occurs */
@@ -1123,7 +1107,7 @@
 
 #if 0
 static CURLcode wscp_done(struct Curl_easy *data,
-                         CURLcode code, bool premature)
+                          CURLcode code, bool premature)
 {
   CURLcode result = CURLE_OK;
   (void)conn;
@@ -1134,7 +1118,7 @@
 }
 
 static CURLcode wscp_doing(struct Curl_easy *data,
-                          bool *dophase_done)
+                           bool *dophase_done)
 {
   CURLcode result = CURLE_OK;
   (void)conn;
@@ -1156,7 +1140,7 @@
 #endif
 
 static CURLcode wsftp_done(struct Curl_easy *data,
-                          CURLcode code, bool premature)
+                           CURLcode code, bool premature)
 {
   struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN);
   (void)premature;
@@ -1169,7 +1153,7 @@
 }
 
 static CURLcode wsftp_doing(struct Curl_easy *data,
-                           bool *dophase_done)
+                            bool *dophase_done)
 {
   CURLcode result = wssh_multi_statemach(data, dophase_done);
 
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c
deleted file mode 100644
index 4b65244..0000000
--- a/Utilities/cmcurl/lib/vtls/bearssl.c
+++ /dev/null
@@ -1,1104 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) Michael Forney, <mforney@mforney.org>
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "../curl_setup.h"
-
-#ifdef USE_BEARSSL
-
-#include <bearssl.h>
-
-#include "bearssl.h"
-#include "cipher_suite.h"
-#include "../urldata.h"
-#include "../sendf.h"
-#include "../curlx/inet_pton.h"
-#include "vtls.h"
-#include "vtls_int.h"
-#include "vtls_scache.h"
-#include "../connect.h"
-#include "../select.h"
-#include "../multiif.h"
-#include "../curl_printf.h"
-
-/* The last #include files should be: */
-#include "../curl_memory.h"
-#include "../memdebug.h"
-
-struct x509_context {
-  const br_x509_class *vtable;
-  br_x509_minimal_context minimal;
-  br_x509_decoder_context decoder;
-  bool verifyhost;
-  bool verifypeer;
-  int cert_num;
-};
-
-struct bearssl_ssl_backend_data {
-  br_ssl_client_context ctx;
-  struct x509_context x509;
-  unsigned char buf[BR_SSL_BUFSIZE_BIDI];
-  br_x509_trust_anchor *anchors;
-  size_t anchors_len;
-  const char *protocols[ALPN_ENTRIES_MAX];
-  /* SSL client context is active */
-  bool active;
-  /* size of pending write, yet to be flushed */
-  size_t pending_write;
-  BIT(sent_shutdown);
-};
-
-struct cafile_parser {
-  CURLcode err;
-  bool in_cert;
-  br_x509_decoder_context xc;
-  /* array of trust anchors loaded from CAfile */
-  br_x509_trust_anchor *anchors;
-  size_t anchors_len;
-  /* buffer for DN data */
-  unsigned char dn[1024];
-  size_t dn_len;
-};
-
-#define CAFILE_SOURCE_PATH 1
-#define CAFILE_SOURCE_BLOB 2
-struct cafile_source {
-  int type;
-  const char *data;
-  size_t len;
-};
-
-static void append_dn(void *ctx, const void *buf, size_t len)
-{
-  struct cafile_parser *ca = ctx;
-
-  if(ca->err != CURLE_OK || !ca->in_cert)
-    return;
-  if(sizeof(ca->dn) - ca->dn_len < len) {
-    ca->err = CURLE_FAILED_INIT;
-    return;
-  }
-  memcpy(ca->dn + ca->dn_len, buf, len);
-  ca->dn_len += len;
-}
-
-static void x509_push(void *ctx, const void *buf, size_t len)
-{
-  struct cafile_parser *ca = ctx;
-
-  if(ca->in_cert)
-    br_x509_decoder_push(&ca->xc, buf, len);
-}
-
-static CURLcode load_cafile(struct cafile_source *source,
-                            br_x509_trust_anchor **anchors,
-                            size_t *anchors_len)
-{
-  struct cafile_parser ca;
-  br_pem_decoder_context pc;
-  br_x509_trust_anchor *ta;
-  size_t ta_size;
-  br_x509_trust_anchor *new_anchors;
-  size_t new_anchors_len;
-  br_x509_pkey *pkey;
-  FILE *fp = 0;
-  unsigned char buf[BUFSIZ];
-  const unsigned char *p = NULL;
-  const char *name;
-  size_t n = 0, i, pushed;
-
-  DEBUGASSERT(source->type == CAFILE_SOURCE_PATH
-              || source->type == CAFILE_SOURCE_BLOB);
-
-  if(source->type == CAFILE_SOURCE_PATH) {
-    fp = fopen(source->data, "rb");
-    if(!fp)
-      return CURLE_SSL_CACERT_BADFILE;
-  }
-
-  if(source->type == CAFILE_SOURCE_BLOB && source->len > (size_t)INT_MAX)
-    return CURLE_SSL_CACERT_BADFILE;
-
-  ca.err = CURLE_OK;
-  ca.in_cert = FALSE;
-  ca.anchors = NULL;
-  ca.anchors_len = 0;
-  br_pem_decoder_init(&pc);
-  br_pem_decoder_setdest(&pc, x509_push, &ca);
-  do {
-    if(source->type == CAFILE_SOURCE_PATH) {
-      n = fread(buf, 1, sizeof(buf), fp);
-      if(n == 0)
-        break;
-      p = buf;
-    }
-    else if(source->type == CAFILE_SOURCE_BLOB) {
-      n = source->len;
-      p = (const unsigned char *) source->data;
-    }
-    while(n) {
-      pushed = br_pem_decoder_push(&pc, p, n);
-      if(ca.err)
-        goto fail;
-      p += pushed;
-      n -= pushed;
-
-      switch(br_pem_decoder_event(&pc)) {
-      case 0:
-        break;
-      case BR_PEM_BEGIN_OBJ:
-        name = br_pem_decoder_name(&pc);
-        if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE"))
-          break;
-        br_x509_decoder_init(&ca.xc, append_dn, &ca);
-        ca.in_cert = TRUE;
-        ca.dn_len = 0;
-        break;
-      case BR_PEM_END_OBJ:
-        if(!ca.in_cert)
-          break;
-        ca.in_cert = FALSE;
-        if(br_x509_decoder_last_error(&ca.xc)) {
-          ca.err = CURLE_SSL_CACERT_BADFILE;
-          goto fail;
-        }
-        /* add trust anchor */
-        if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) {
-          ca.err = CURLE_OUT_OF_MEMORY;
-          goto fail;
-        }
-        new_anchors_len = ca.anchors_len + 1;
-        new_anchors = realloc(ca.anchors,
-                              new_anchors_len * sizeof(ca.anchors[0]));
-        if(!new_anchors) {
-          ca.err = CURLE_OUT_OF_MEMORY;
-          goto fail;
-        }
-        ca.anchors = new_anchors;
-        ca.anchors_len = new_anchors_len;
-        ta = &ca.anchors[ca.anchors_len - 1];
-        ta->dn.data = NULL;
-        ta->flags = 0;
-        if(br_x509_decoder_isCA(&ca.xc))
-          ta->flags |= BR_X509_TA_CA;
-        pkey = br_x509_decoder_get_pkey(&ca.xc);
-        if(!pkey) {
-          ca.err = CURLE_SSL_CACERT_BADFILE;
-          goto fail;
-        }
-        ta->pkey = *pkey;
-
-        /* calculate space needed for trust anchor data */
-        ta_size = ca.dn_len;
-        switch(pkey->key_type) {
-        case BR_KEYTYPE_RSA:
-          ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen;
-          break;
-        case BR_KEYTYPE_EC:
-          ta_size += pkey->key.ec.qlen;
-          break;
-        default:
-          ca.err = CURLE_FAILED_INIT;
-          goto fail;
-        }
-
-        /* fill in trust anchor DN and public key data */
-        ta->dn.data = malloc(ta_size);
-        if(!ta->dn.data) {
-          ca.err = CURLE_OUT_OF_MEMORY;
-          goto fail;
-        }
-        memcpy(ta->dn.data, ca.dn, ca.dn_len);
-        ta->dn.len = ca.dn_len;
-        switch(pkey->key_type) {
-        case BR_KEYTYPE_RSA:
-          ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len;
-          memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen);
-          ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen;
-          memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen);
-          break;
-        case BR_KEYTYPE_EC:
-          ta->pkey.key.ec.q = ta->dn.data + ta->dn.len;
-          memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen);
-          break;
-        }
-        break;
-      default:
-        ca.err = CURLE_SSL_CACERT_BADFILE;
-        goto fail;
-      }
-    }
-  } while(source->type != CAFILE_SOURCE_BLOB);
-  if(fp && ferror(fp))
-    ca.err = CURLE_READ_ERROR;
-  else if(ca.in_cert)
-    ca.err = CURLE_SSL_CACERT_BADFILE;
-
-fail:
-  if(fp)
-    fclose(fp);
-  if(ca.err == CURLE_OK) {
-    *anchors = ca.anchors;
-    *anchors_len = ca.anchors_len;
-  }
-  else {
-    for(i = 0; i < ca.anchors_len; ++i)
-      free(ca.anchors[i].dn.data);
-    free(ca.anchors);
-  }
-
-  return ca.err;
-}
-
-static void x509_start_chain(const br_x509_class **ctx,
-                             const char *server_name)
-{
-  struct x509_context *x509 = (struct x509_context *)ctx;
-
-  if(!x509->verifypeer) {
-    x509->cert_num = 0;
-    return;
-  }
-
-  if(!x509->verifyhost)
-    server_name = NULL;
-  x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name);
-}
-
-static void x509_start_cert(const br_x509_class **ctx, uint32_t length)
-{
-  struct x509_context *x509 = (struct x509_context *)ctx;
-
-  if(!x509->verifypeer) {
-    /* Only decode the first cert in the chain to obtain the public key */
-    if(x509->cert_num == 0)
-      br_x509_decoder_init(&x509->decoder, NULL, NULL);
-    return;
-  }
-
-  x509->minimal.vtable->start_cert(&x509->minimal.vtable, length);
-}
-
-static void x509_append(const br_x509_class **ctx, const unsigned char *buf,
-                        size_t len)
-{
-  struct x509_context *x509 = (struct x509_context *)ctx;
-
-  if(!x509->verifypeer) {
-    if(x509->cert_num == 0)
-      br_x509_decoder_push(&x509->decoder, buf, len);
-    return;
-  }
-
-  x509->minimal.vtable->append(&x509->minimal.vtable, buf, len);
-}
-
-static void x509_end_cert(const br_x509_class **ctx)
-{
-  struct x509_context *x509 = (struct x509_context *)ctx;
-
-  if(!x509->verifypeer) {
-    x509->cert_num++;
-    return;
-  }
-
-  x509->minimal.vtable->end_cert(&x509->minimal.vtable);
-}
-
-static unsigned x509_end_chain(const br_x509_class **ctx)
-{
-  struct x509_context *x509 = (struct x509_context *)ctx;
-
-  if(!x509->verifypeer) {
-    return (unsigned)br_x509_decoder_last_error(&x509->decoder);
-  }
-
-  return x509->minimal.vtable->end_chain(&x509->minimal.vtable);
-}
-
-static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx,
-                                         unsigned *usages)
-{
-  struct x509_context *x509 = (struct x509_context *)CURL_UNCONST(ctx);
-
-  if(!x509->verifypeer) {
-    /* Nothing in the chain is verified, just return the public key of the
-       first certificate and allow its usage for both TLS_RSA_* and
-       TLS_ECDHE_* */
-    if(usages)
-      *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN;
-    return br_x509_decoder_get_pkey(&x509->decoder);
-  }
-
-  return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages);
-}
-
-static const br_x509_class x509_vtable = {
-  sizeof(struct x509_context),
-  x509_start_chain,
-  x509_start_cert,
-  x509_append,
-  x509_end_cert,
-  x509_end_chain,
-  x509_get_pkey
-};
-
-static CURLcode
-bearssl_set_ssl_version_min_max(struct Curl_easy *data,
-                                br_ssl_engine_context *ssl_eng,
-                                struct ssl_primary_config *conn_config)
-{
-  unsigned version_min, version_max;
-
-  switch(conn_config->version) {
-  case CURL_SSLVERSION_DEFAULT:
-  case CURL_SSLVERSION_TLSv1:
-  case CURL_SSLVERSION_TLSv1_0:
-    version_min = BR_TLS10;
-    break;
-  case CURL_SSLVERSION_TLSv1_1:
-    version_min = BR_TLS11;
-    break;
-  case CURL_SSLVERSION_TLSv1_2:
-    version_min = BR_TLS12;
-    break;
-  case CURL_SSLVERSION_TLSv1_3:
-    failf(data, "BearSSL: does not support TLS 1.3");
-    return CURLE_SSL_CONNECT_ERROR;
-  default:
-    failf(data, "BearSSL: unsupported minimum TLS version value");
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-
-  switch(conn_config->version_max) {
-  case CURL_SSLVERSION_MAX_DEFAULT:
-  case CURL_SSLVERSION_MAX_NONE:
-  case CURL_SSLVERSION_MAX_TLSv1_3:
-  case CURL_SSLVERSION_MAX_TLSv1_2:
-    version_max = BR_TLS12;
-    break;
-  case CURL_SSLVERSION_MAX_TLSv1_1:
-    version_max = BR_TLS11;
-    break;
-  case CURL_SSLVERSION_MAX_TLSv1_0:
-    version_max = BR_TLS10;
-    break;
-  default:
-    failf(data, "BearSSL: unsupported maximum TLS version value");
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-
-  br_ssl_engine_set_versions(ssl_eng, version_min, version_max);
-
-  return CURLE_OK;
-}
-
-static const uint16_t ciphertable[] = {
-  /* RFC 2246 TLS 1.0 */
-  BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA,                        /* 0x000A */
-
-  /* RFC 3268 TLS 1.0 AES */
-  BR_TLS_RSA_WITH_AES_128_CBC_SHA,                         /* 0x002F */
-  BR_TLS_RSA_WITH_AES_256_CBC_SHA,                         /* 0x0035 */
-
-  /* RFC 5246 TLS 1.2 */
-  BR_TLS_RSA_WITH_AES_128_CBC_SHA256,                      /* 0x003C */
-  BR_TLS_RSA_WITH_AES_256_CBC_SHA256,                      /* 0x003D */
-
-  /* RFC 5288 TLS 1.2 AES GCM */
-  BR_TLS_RSA_WITH_AES_128_GCM_SHA256,                      /* 0x009C */
-  BR_TLS_RSA_WITH_AES_256_GCM_SHA384,                      /* 0x009D */
-
-  /* RFC 4492 TLS 1.0 ECC */
-  BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,                 /* 0xC003 */
-  BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,                  /* 0xC004 */
-  BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,                  /* 0xC005 */
-  BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,                /* 0xC008 */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,                 /* 0xC009 */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,                 /* 0xC00A */
-  BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,                   /* 0xC00D */
-  BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,                    /* 0xC00E */
-  BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,                    /* 0xC00F */
-  BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,                  /* 0xC012 */
-  BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,                   /* 0xC013 */
-  BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,                   /* 0xC014 */
-
-  /* RFC 5289 TLS 1.2 ECC HMAC SHA256/384 */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,              /* 0xC023 */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,              /* 0xC024 */
-  BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,               /* 0xC025 */
-  BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,               /* 0xC026 */
-  BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,                /* 0xC027 */
-  BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,                /* 0xC028 */
-  BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,                 /* 0xC029 */
-  BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,                 /* 0xC02A */
-
-  /* RFC 5289 TLS 1.2 GCM */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,              /* 0xC02B */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,              /* 0xC02C */
-  BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,               /* 0xC02D */
-  BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,               /* 0xC02E */
-  BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,                /* 0xC02F */
-  BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,                /* 0xC030 */
-  BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,                 /* 0xC031 */
-  BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,                 /* 0xC032 */
-
-#ifdef BR_TLS_RSA_WITH_AES_128_CCM
-  /* RFC 6655 TLS 1.2 CCM
-     Supported since BearSSL 0.6 */
-  BR_TLS_RSA_WITH_AES_128_CCM,                             /* 0xC09C */
-  BR_TLS_RSA_WITH_AES_256_CCM,                             /* 0xC09D */
-  BR_TLS_RSA_WITH_AES_128_CCM_8,                           /* 0xC0A0 */
-  BR_TLS_RSA_WITH_AES_256_CCM_8,                           /* 0xC0A1 */
-
-  /* RFC 7251 TLS 1.2 ECC CCM
-     Supported since BearSSL 0.6 */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,                     /* 0xC0AC */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,                     /* 0xC0AD */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,                   /* 0xC0AE */
-  BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,                   /* 0xC0AF */
-#endif
-
-  /* RFC 7905 TLS 1.2 ChaCha20-Poly1305
-     Supported since BearSSL 0.2 */
-  BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,          /* 0xCCA8 */
-  BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,        /* 0xCCA9 */
-};
-
-#define NUM_OF_CIPHERS CURL_ARRAYSIZE(ciphertable)
-
-static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
-                                             br_ssl_engine_context *ssl_eng,
-                                             const char *ciphers)
-{
-  uint16_t selected[NUM_OF_CIPHERS];
-  size_t count = 0, i;
-  const char *ptr, *end;
-
-  for(ptr = ciphers; ptr[0] != '\0' && count < NUM_OF_CIPHERS; ptr = end) {
-    uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end);
-
-    /* Check if cipher is supported */
-    if(id) {
-      for(i = 0; i < NUM_OF_CIPHERS && ciphertable[i] != id; i++);
-      if(i == NUM_OF_CIPHERS)
-        id = 0;
-    }
-    if(!id) {
-      if(ptr[0] != '\0')
-        infof(data, "BearSSL: unknown cipher in list: \"%.*s\"",
-              (int) (end - ptr), ptr);
-      continue;
-    }
-
-    /* No duplicates allowed */
-    for(i = 0; i < count && selected[i] != id; i++);
-    if(i < count) {
-      infof(data, "BearSSL: duplicate cipher in list: \"%.*s\"",
-            (int) (end - ptr), ptr);
-      continue;
-    }
-
-    selected[count++] = id;
-  }
-
-  if(count == 0) {
-    failf(data, "BearSSL: no supported cipher in list");
-    return CURLE_SSL_CIPHER;
-  }
-
-  br_ssl_engine_set_suites(ssl_eng, selected, count);
-  return CURLE_OK;
-}
-
-static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
-                                      struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
-  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
-  const char * const ssl_cafile =
-    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
-    (ca_info_blob ? NULL : conn_config->CAfile);
-  const char *hostname = connssl->peer.hostname;
-  const bool verifypeer = conn_config->verifypeer;
-  const bool verifyhost = conn_config->verifyhost;
-  CURLcode ret;
-  int session_set = 0;
-
-  DEBUGASSERT(backend);
-  CURL_TRC_CF(data, cf, "connect_step1");
-
-  if(verifypeer) {
-    if(ca_info_blob) {
-      struct cafile_source source;
-      source.type = CAFILE_SOURCE_BLOB;
-      source.data = ca_info_blob->data;
-      source.len = ca_info_blob->len;
-
-      CURL_TRC_CF(data, cf, "connect_step1, load ca_info_blob");
-      ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
-      if(ret != CURLE_OK) {
-        failf(data, "error importing CA certificate blob");
-        return ret;
-      }
-    }
-
-    if(ssl_cafile) {
-      struct cafile_source source;
-      source.type = CAFILE_SOURCE_PATH;
-      source.data = ssl_cafile;
-      source.len = 0;
-
-      CURL_TRC_CF(data, cf, "connect_step1, load cafile");
-      ret = load_cafile(&source, &backend->anchors, &backend->anchors_len);
-      if(ret != CURLE_OK) {
-        failf(data, "error setting certificate verify locations."
-              " CAfile: %s", ssl_cafile);
-        return ret;
-      }
-    }
-  }
-
-  /* initialize SSL context */
-  br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal,
-                          backend->anchors, backend->anchors_len);
-
-  ret = bearssl_set_ssl_version_min_max(data, &backend->ctx.eng, conn_config);
-  if(ret != CURLE_OK)
-    return ret;
-
-  br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf,
-                           sizeof(backend->buf), 1);
-
-  if(conn_config->cipher_list) {
-    /* Override the ciphers as specified. For the default cipher list see the
-       BearSSL source code of br_ssl_client_init_full() */
-    CURL_TRC_CF(data, cf, "connect_step1, set ciphers");
-    ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng,
-                                       conn_config->cipher_list);
-    if(ret)
-      return ret;
-  }
-
-  /* initialize X.509 context */
-  backend->x509.vtable = &x509_vtable;
-  backend->x509.verifypeer = verifypeer;
-  backend->x509.verifyhost = verifyhost;
-  br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
-
-  if(ssl_config->primary.cache_session) {
-    struct Curl_ssl_session *sc_session = NULL;
-
-    ret = Curl_ssl_scache_take(cf, data, connssl->peer.scache_key,
-                               &sc_session);
-    if(!ret && sc_session && sc_session->sdata && sc_session->sdata_len) {
-      const br_ssl_session_parameters *session;
-      session = (const br_ssl_session_parameters *)sc_session->sdata;
-      br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
-      session_set = 1;
-      infof(data, "BearSSL: reusing session ID");
-      /* single use of sessions */
-      Curl_ssl_scache_return(cf, data, connssl->peer.scache_key, sc_session);
-    }
-  }
-
-  if(connssl->alpn) {
-    struct alpn_proto_buf proto;
-    size_t i;
-
-    for(i = 0; i < connssl->alpn->count; ++i) {
-      backend->protocols[i] = connssl->alpn->entries[i];
-    }
-    br_ssl_engine_set_protocol_names(&backend->ctx.eng, backend->protocols,
-                                     connssl->alpn->count);
-    Curl_alpn_to_proto_str(&proto, connssl->alpn);
-    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
-  }
-
-  if(connssl->peer.type != CURL_SSL_PEER_DNS) {
-    if(verifyhost) {
-      failf(data, "BearSSL: "
-            "host verification of IP address is not supported");
-      return CURLE_PEER_FAILED_VERIFICATION;
-    }
-    hostname = NULL;
-  }
-  else {
-    if(!connssl->peer.sni) {
-      failf(data, "Failed to set SNI");
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-    hostname = connssl->peer.sni;
-    CURL_TRC_CF(data, cf, "connect_step1, SNI set");
-  }
-
-  /* give application a chance to interfere with SSL set up. */
-  if(data->set.ssl.fsslctx) {
-    Curl_set_in_callback(data, TRUE);
-    ret = (*data->set.ssl.fsslctx)(data, &backend->ctx,
-                                   data->set.ssl.fsslctxp);
-    Curl_set_in_callback(data, FALSE);
-    if(ret) {
-      failf(data, "BearSSL: error signaled by ssl ctx callback");
-      return ret;
-    }
-  }
-
-  if(!br_ssl_client_reset(&backend->ctx, hostname, session_set))
-    return CURLE_FAILED_INIT;
-  backend->active = TRUE;
-
-  connssl->connecting_state = ssl_connect_2;
-
-  return CURLE_OK;
-}
-
-static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  unsigned target)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  unsigned state;
-  unsigned char *buf;
-  size_t len;
-  ssize_t ret;
-  CURLcode result;
-  int err;
-
-  DEBUGASSERT(backend);
-
-  connssl->io_need = CURL_SSL_IO_NEED_NONE;
-  for(;;) {
-    state = br_ssl_engine_current_state(&backend->ctx.eng);
-    if(state & BR_SSL_CLOSED) {
-      err = br_ssl_engine_last_error(&backend->ctx.eng);
-      switch(err) {
-      case BR_ERR_OK:
-        /* TLS close notify */
-        if(connssl->state != ssl_connection_complete) {
-          failf(data, "SSL: connection closed during handshake");
-          return CURLE_SSL_CONNECT_ERROR;
-        }
-        return CURLE_OK;
-      case BR_ERR_X509_EXPIRED:
-        failf(data, "SSL: X.509 verification: "
-              "certificate is expired or not yet valid");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case BR_ERR_X509_BAD_SERVER_NAME:
-        failf(data, "SSL: X.509 verification: "
-              "expected server name was not found in the chain");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case BR_ERR_X509_NOT_TRUSTED:
-        failf(data, "SSL: X.509 verification: "
-              "chain could not be linked to a trust anchor");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      default:;
-      }
-      failf(data, "BearSSL: connection error 0x%04x", err);
-      /* X.509 errors are documented to have the range 32..63 */
-      if(err >= 32 && err < 64)
-        return CURLE_PEER_FAILED_VERIFICATION;
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-    if(state & target)
-      return CURLE_OK;
-    if(state & BR_SSL_SENDREC) {
-      buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
-      ret = Curl_conn_cf_send(cf->next, data, (const char *)buf, len, FALSE,
-                              &result);
-      CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
-      if(ret <= 0) {
-        if(result == CURLE_AGAIN)
-          connssl->io_need |= CURL_SSL_IO_NEED_SEND;
-        return result;
-      }
-      br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
-    }
-    else if(state & BR_SSL_RECVREC) {
-      buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
-      ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
-      CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
-      if(ret == 0) {
-        failf(data, "SSL: EOF without close notify");
-        return CURLE_RECV_ERROR;
-      }
-      if(ret <= 0) {
-        if(result == CURLE_AGAIN)
-          connssl->io_need |= CURL_SSL_IO_NEED_RECV;
-        return result;
-      }
-      br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
-    }
-  }
-}
-
-static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
-                                      struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  br_ssl_session_parameters session;
-  char cipher_str[64];
-  CURLcode ret;
-
-  DEBUGASSERT(backend);
-  CURL_TRC_CF(data, cf, "connect_step2");
-
-  ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
-  if(ret == CURLE_AGAIN)
-    return CURLE_OK;
-  if(ret == CURLE_OK) {
-    unsigned int tver;
-    int subver = 0;
-
-    if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
-      failf(data, "SSL: connection closed during handshake");
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-    connssl->connecting_state = ssl_connect_3;
-    /* Informational message */
-    tver = br_ssl_engine_get_version(&backend->ctx.eng);
-    switch(tver) {
-    case BR_TLS12:
-      subver = 2; /* 1.2 */
-      break;
-    case BR_TLS11:
-      subver = 1; /* 1.1 */
-      break;
-    case BR_TLS10: /* 1.0 */
-    default: /* unknown, leave it at zero */
-      break;
-    }
-    br_ssl_engine_get_session_parameters(&backend->ctx.eng, &session);
-    Curl_cipher_suite_get_str(session.cipher_suite, cipher_str,
-                              sizeof(cipher_str), TRUE);
-    infof(data, "BearSSL: TLS v1.%d connection using %s", subver,
-          cipher_str);
-  }
-  return ret;
-}
-
-static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
-                                      struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-  CURLcode ret;
-
-  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
-  DEBUGASSERT(backend);
-  CURL_TRC_CF(data, cf, "connect_step3");
-
-  if(connssl->alpn) {
-    const char *proto;
-
-    proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
-    Curl_alpn_set_negotiated(cf, data, connssl, (const unsigned char *)proto,
-                             proto ? strlen(proto) : 0);
-  }
-
-  if(ssl_config->primary.cache_session) {
-    struct Curl_ssl_session *sc_session;
-    br_ssl_session_parameters *session;
-
-    session = malloc(sizeof(*session));
-    if(!session)
-      return CURLE_OUT_OF_MEMORY;
-    br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
-    ret = Curl_ssl_session_create((unsigned char *)session, sizeof(*session),
-                                  (int)session->version,
-                                  connssl->negotiated.alpn,
-                                  0, 0, &sc_session);
-    if(!ret) {
-      ret = Curl_ssl_scache_put(cf, data, connssl->peer.scache_key,
-                                sc_session);
-      /* took ownership of `sc_session` */
-    }
-    if(ret)
-      return ret;
-  }
-
-  connssl->connecting_state = ssl_connect_done;
-
-  return CURLE_OK;
-}
-
-static ssize_t bearssl_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                            const void *buf, size_t len, CURLcode *err)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  unsigned char *app;
-  size_t applen;
-
-  DEBUGASSERT(backend);
-
-  for(;;) {
-    *err = bearssl_run_until(cf, data, BR_SSL_SENDAPP);
-    if(*err)
-      return -1;
-    app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen);
-    if(!app) {
-      failf(data, "SSL: connection closed during write");
-      *err = CURLE_SEND_ERROR;
-      return -1;
-    }
-    if(backend->pending_write) {
-      applen = backend->pending_write;
-      backend->pending_write = 0;
-      return applen;
-    }
-    if(applen > len)
-      applen = len;
-    memcpy(app, buf, applen);
-    br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen);
-    br_ssl_engine_flush(&backend->ctx.eng, 0);
-    backend->pending_write = applen;
-  }
-}
-
-static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                            char *buf, size_t len, CURLcode *err)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  unsigned char *app;
-  size_t applen;
-
-  DEBUGASSERT(backend);
-
-  *err = bearssl_run_until(cf, data, BR_SSL_RECVAPP);
-  if(*err != CURLE_OK)
-    return -1;
-  app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen);
-  if(!app)
-    return 0;
-  if(applen > len)
-    applen = len;
-  memcpy(buf, app, applen);
-  br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen);
-
-  return applen;
-}
-
-static CURLcode bearssl_connect(struct Curl_cfilter *cf,
-                                struct Curl_easy *data,
-                                bool *done)
-{
-  CURLcode ret;
-  struct ssl_connect_data *connssl = cf->ctx;
-
-  CURL_TRC_CF(data, cf, "connect()");
-  /* check if the connection has already been established */
-  if(ssl_connection_complete == connssl->state) {
-    CURL_TRC_CF(data, cf, "connect_common, connected");
-    *done = TRUE;
-    return CURLE_OK;
-  }
-
-  *done = FALSE;
-  connssl->io_need = CURL_SSL_IO_NEED_NONE;
-
-  if(ssl_connect_1 == connssl->connecting_state) {
-    ret = bearssl_connect_step1(cf, data);
-    if(ret)
-      return ret;
-  }
-
-  if(ssl_connect_2 == connssl->connecting_state) {
-    ret = bearssl_connect_step2(cf, data);
-    if(ret)
-      return ret;
-  }
-
-  if(ssl_connect_3 == connssl->connecting_state) {
-    ret = bearssl_connect_step3(cf, data);
-    if(ret)
-      return ret;
-  }
-
-  if(ssl_connect_done == connssl->connecting_state) {
-    connssl->state = ssl_connection_complete;
-    *done = TRUE;
-  }
-
-  return CURLE_OK;
-}
-
-static size_t bearssl_version(char *buffer, size_t size)
-{
-  return msnprintf(buffer, size, "BearSSL");
-}
-
-static bool bearssl_data_pending(struct Curl_cfilter *cf,
-                                 const struct Curl_easy *data)
-{
-  struct ssl_connect_data *ctx = cf->ctx;
-  struct bearssl_ssl_backend_data *backend;
-
-  (void)data;
-  DEBUGASSERT(ctx && ctx->backend);
-  backend = (struct bearssl_ssl_backend_data *)ctx->backend;
-  return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP;
-}
-
-static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
-                               unsigned char *entropy, size_t length)
-{
-  static br_hmac_drbg_context ctx;
-  static bool seeded = FALSE;
-
-  if(!seeded) {
-    br_prng_seeder seeder;
-
-    br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0);
-    seeder = br_prng_seeder_system(NULL);
-    if(!seeder || !seeder(&ctx.vtable))
-      return CURLE_FAILED_INIT;
-    seeded = TRUE;
-  }
-  br_hmac_drbg_generate(&ctx, entropy, length);
-
-  return CURLE_OK;
-}
-
-static void *bearssl_get_internals(struct ssl_connect_data *connssl,
-                                   CURLINFO info UNUSED_PARAM)
-{
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  DEBUGASSERT(backend);
-  return &backend->ctx;
-}
-
-static CURLcode bearssl_shutdown(struct Curl_cfilter *cf,
-                                 struct Curl_easy *data,
-                                 bool send_shutdown, bool *done)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  CURLcode result;
-
-  DEBUGASSERT(backend);
-  if(!backend->active || cf->shutdown) {
-    *done = TRUE;
-    return CURLE_OK;
-  }
-
-  *done = FALSE;
-  if(!backend->sent_shutdown) {
-    (void)send_shutdown; /* unknown how to suppress our close notify */
-    br_ssl_engine_close(&backend->ctx.eng);
-    backend->sent_shutdown = TRUE;
-  }
-
-  result = bearssl_run_until(cf, data, BR_SSL_CLOSED);
-  if(result == CURLE_OK) {
-    *done = TRUE;
-  }
-  else if(result == CURLE_AGAIN) {
-    CURL_TRC_CF(data, cf, "shutdown EAGAIN, io_need=%x", connssl->io_need);
-    result = CURLE_OK;
-  }
-  else
-    CURL_TRC_CF(data, cf, "shutdown error: %d", result);
-
-  cf->shutdown = (result || *done);
-  return result;
-}
-
-static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct bearssl_ssl_backend_data *backend =
-    (struct bearssl_ssl_backend_data *)connssl->backend;
-  size_t i;
-
-  (void)data;
-  DEBUGASSERT(backend);
-
-  backend->active = FALSE;
-  if(backend->anchors) {
-    for(i = 0; i < backend->anchors_len; ++i)
-      free(backend->anchors[i].dn.data);
-    Curl_safefree(backend->anchors);
-  }
-}
-
-static CURLcode bearssl_sha256sum(const unsigned char *input,
-                                  size_t inputlen,
-                                  unsigned char *sha256sum,
-                                  size_t sha256len UNUSED_PARAM)
-{
-  br_sha256_context ctx;
-
-  br_sha256_init(&ctx);
-  br_sha256_update(&ctx, input, inputlen);
-  br_sha256_out(&ctx, sha256sum);
-  return CURLE_OK;
-}
-
-const struct Curl_ssl Curl_ssl_bearssl = {
-  { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
-
-  SSLSUPP_CAINFO_BLOB |
-  SSLSUPP_SSL_CTX |
-  SSLSUPP_HTTPS_PROXY |
-  SSLSUPP_CIPHER_LIST,
-
-  sizeof(struct bearssl_ssl_backend_data),
-
-  NULL,                            /* init */
-  NULL,                            /* cleanup */
-  bearssl_version,                 /* version */
-  bearssl_shutdown,                /* shutdown */
-  bearssl_data_pending,            /* data_pending */
-  bearssl_random,                  /* random */
-  NULL,                            /* cert_status_request */
-  bearssl_connect,                 /* connect */
-  Curl_ssl_adjust_pollset,         /* adjust_pollset */
-  bearssl_get_internals,           /* get_internals */
-  bearssl_close,                   /* close_one */
-  NULL,                            /* close_all */
-  NULL,                            /* set_engine */
-  NULL,                            /* set_engine_default */
-  NULL,                            /* engines_list */
-  NULL,                            /* false_start */
-  bearssl_sha256sum,               /* sha256sum */
-  bearssl_recv,                    /* recv decrypted data */
-  bearssl_send,                    /* send data to encrypt */
-  NULL,                            /* get_channel_binding */
-};
-
-#endif /* USE_BEARSSL */
diff --git a/Utilities/cmcurl/lib/vtls/cipher_suite.c b/Utilities/cmcurl/lib/vtls/cipher_suite.c
index d058bd3..cefc92c 100644
--- a/Utilities/cmcurl/lib/vtls/cipher_suite.c
+++ b/Utilities/cmcurl/lib/vtls/cipher_suite.c
@@ -23,11 +23,9 @@
  ***************************************************************************/
 #include "../curl_setup.h"
 
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
-    defined(USE_BEARSSL) || defined(USE_RUSTLS)
+#if defined(USE_MBEDTLS) || defined(USE_RUSTLS)
 #include "cipher_suite.h"
 #include "../curl_printf.h"
-#include "../strcase.h"
 #include <string.h>
 
 /*
@@ -90,21 +88,6 @@
   "CAMELLIA128" "\0"
   "CAMELLIA256" "\0"
 #endif
-#if defined(USE_SECTRANSP)
-  "40" "\0"
-  "ADH" "\0"
-  "AECDH" "\0"
-  "anon" "\0"
-  "DES40" "\0"
-  "DH" "\0"
-  "DSS" "\0"
-  "EDH" "\0"
-  "EXP" "\0"
-  "EXPORT" "\0"
-  "IDEA" "\0"
-  "RC2" "\0"
-  "RC4" "\0"
-#endif
 ;
 /* Indexes of above cs_txt */
 enum {
@@ -146,21 +129,6 @@
   CS_TXT_IDX_CAMELLIA128,
   CS_TXT_IDX_CAMELLIA256,
 #endif
-#if defined(USE_SECTRANSP)
-  CS_TXT_IDX_40,
-  CS_TXT_IDX_ADH,
-  CS_TXT_IDX_AECDH,
-  CS_TXT_IDX_anon,
-  CS_TXT_IDX_DES40,
-  CS_TXT_IDX_DH,
-  CS_TXT_IDX_DSS,
-  CS_TXT_IDX_EDH,
-  CS_TXT_IDX_EXP,
-  CS_TXT_IDX_EXPORT,
-  CS_TXT_IDX_IDEA,
-  CS_TXT_IDX_RC2,
-  CS_TXT_IDX_RC4,
-#endif
   CS_TXT_LEN,
 };
 
@@ -192,7 +160,7 @@
 /* !checksrc! disable COMMANOSPACE all */
 static const struct cs_entry cs_list [] = {
   /* TLS 1.3 ciphers */
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_RUSTLS)
+#if defined(USE_MBEDTLS) || defined(USE_RUSTLS)
   CS_ENTRY(0x1301, TLS,AES,128,GCM,SHA256,,,),
   CS_ENTRY(0x1302, TLS,AES,256,GCM,SHA384,,,),
   CS_ENTRY(0x1303, TLS,CHACHA20,POLY1305,SHA256,,,,),
@@ -212,7 +180,7 @@
   CS_ENTRY(0xCCA8, ECDHE,RSA,CHACHA20,POLY1305,,,,),
   CS_ENTRY(0xCCA9, TLS,ECDHE,ECDSA,WITH,CHACHA20,POLY1305,SHA256,),
   CS_ENTRY(0xCCA9, ECDHE,ECDSA,CHACHA20,POLY1305,,,,),
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_BEARSSL)
+#if defined(USE_MBEDTLS)
   CS_ENTRY(0x002F, TLS,RSA,WITH,AES,128,CBC,SHA,),
   CS_ENTRY(0x002F, AES128,SHA,,,,,,),
   CS_ENTRY(0x0035, TLS,RSA,WITH,AES,256,CBC,SHA,),
@@ -266,7 +234,7 @@
   CS_ENTRY(0xC032, TLS,ECDH,RSA,WITH,AES,256,GCM,SHA384),
   CS_ENTRY(0xC032, ECDH,RSA,AES256,GCM,SHA384,,,),
 #endif
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS)
+#if defined(USE_MBEDTLS)
   CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,),
   CS_ENTRY(0x0001, NULL,MD5,,,,,,),
   CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,),
@@ -354,19 +322,7 @@
   CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,),
   CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,),
 #endif
-#if defined(USE_SECTRANSP) || defined(USE_BEARSSL)
-  CS_ENTRY(0x000A, TLS,RSA,WITH,3DES,EDE,CBC,SHA,),
-  CS_ENTRY(0x000A, DES,CBC3,SHA,,,,,),
-  CS_ENTRY(0xC003, TLS,ECDH,ECDSA,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0xC003, ECDH,ECDSA,DES,CBC3,SHA,,,),
-  CS_ENTRY(0xC008, TLS,ECDHE,ECDSA,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0xC008, ECDHE,ECDSA,DES,CBC3,SHA,,,),
-  CS_ENTRY(0xC00D, TLS,ECDH,RSA,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0xC00D, ECDH,RSA,DES,CBC3,SHA,,,),
-  CS_ENTRY(0xC012, TLS,ECDHE,RSA,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0xC012, ECDHE,RSA,DES,CBC3,SHA,,,),
-#endif
-#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
+#if defined(USE_MBEDTLS)
   CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,),
   CS_ENTRY(0xC09C, AES128,CCM,,,,,,),
   CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,),
@@ -384,141 +340,6 @@
   CS_ENTRY(0xC0AF, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,8),
   CS_ENTRY(0xC0AF, ECDHE,ECDSA,AES256,CCM8,,,,),
 #endif
-#if defined(USE_SECTRANSP)
-  /* entries marked bc are backward compatible aliases for old OpenSSL names */
-  CS_ENTRY(0x0003, TLS,RSA,EXPORT,WITH,RC4,40,MD5,),
-  CS_ENTRY(0x0003, EXP,RC4,MD5,,,,,),
-  CS_ENTRY(0x0004, TLS,RSA,WITH,RC4,128,MD5,,),
-  CS_ENTRY(0x0004, RC4,MD5,,,,,,),
-  CS_ENTRY(0x0005, TLS,RSA,WITH,RC4,128,SHA,,),
-  CS_ENTRY(0x0005, RC4,SHA,,,,,,),
-  CS_ENTRY(0x0006, TLS,RSA,EXPORT,WITH,RC2,CBC,40,MD5),
-  CS_ENTRY(0x0006, EXP,RC2,CBC,MD5,,,,),
-  CS_ENTRY(0x0007, TLS,RSA,WITH,IDEA,CBC,SHA,,),
-  CS_ENTRY(0x0007, IDEA,CBC,SHA,,,,,),
-  CS_ENTRY(0x0008, TLS,RSA,EXPORT,WITH,DES40,CBC,SHA,),
-  CS_ENTRY(0x0008, EXP,DES,CBC,SHA,,,,),
-  CS_ENTRY(0x0009, TLS,RSA,WITH,DES,CBC,SHA,,),
-  CS_ENTRY(0x0009, DES,CBC,SHA,,,,,),
-  CS_ENTRY(0x000B, TLS,DH,DSS,EXPORT,WITH,DES40,CBC,SHA),
-  CS_ENTRY(0x000B, EXP,DH,DSS,DES,CBC,SHA,,),
-  CS_ENTRY(0x000C, TLS,DH,DSS,WITH,DES,CBC,SHA,),
-  CS_ENTRY(0x000C, DH,DSS,DES,CBC,SHA,,,),
-  CS_ENTRY(0x000D, TLS,DH,DSS,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0x000D, DH,DSS,DES,CBC3,SHA,,,),
-  CS_ENTRY(0x000E, TLS,DH,RSA,EXPORT,WITH,DES40,CBC,SHA),
-  CS_ENTRY(0x000E, EXP,DH,RSA,DES,CBC,SHA,,),
-  CS_ENTRY(0x000F, TLS,DH,RSA,WITH,DES,CBC,SHA,),
-  CS_ENTRY(0x000F, DH,RSA,DES,CBC,SHA,,,),
-  CS_ENTRY(0x0010, TLS,DH,RSA,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0x0010, DH,RSA,DES,CBC3,SHA,,,),
-  CS_ENTRY(0x0011, TLS,DHE,DSS,EXPORT,WITH,DES40,CBC,SHA),
-  CS_ENTRY(0x0011, EXP,DHE,DSS,DES,CBC,SHA,,),
-  CS_ENTRY(0x0011, EXP,EDH,DSS,DES,CBC,SHA,,), /* bc */
-  CS_ENTRY(0x0012, TLS,DHE,DSS,WITH,DES,CBC,SHA,),
-  CS_ENTRY(0x0012, DHE,DSS,DES,CBC,SHA,,,),
-  CS_ENTRY(0x0012, EDH,DSS,DES,CBC,SHA,,,), /* bc */
-  CS_ENTRY(0x0013, TLS,DHE,DSS,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0x0013, DHE,DSS,DES,CBC3,SHA,,,),
-  CS_ENTRY(0x0013, EDH,DSS,DES,CBC3,SHA,,,), /* bc */
-  CS_ENTRY(0x0014, TLS,DHE,RSA,EXPORT,WITH,DES40,CBC,SHA),
-  CS_ENTRY(0x0014, EXP,DHE,RSA,DES,CBC,SHA,,),
-  CS_ENTRY(0x0014, EXP,EDH,RSA,DES,CBC,SHA,,), /* bc */
-  CS_ENTRY(0x0015, TLS,DHE,RSA,WITH,DES,CBC,SHA,),
-  CS_ENTRY(0x0015, DHE,RSA,DES,CBC,SHA,,,),
-  CS_ENTRY(0x0015, EDH,RSA,DES,CBC,SHA,,,), /* bc */
-  CS_ENTRY(0x0016, TLS,DHE,RSA,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0x0016, DHE,RSA,DES,CBC3,SHA,,,),
-  CS_ENTRY(0x0016, EDH,RSA,DES,CBC3,SHA,,,), /* bc */
-  CS_ENTRY(0x0017, TLS,DH,anon,EXPORT,WITH,RC4,40,MD5),
-  CS_ENTRY(0x0017, EXP,ADH,RC4,MD5,,,,),
-  CS_ENTRY(0x0018, TLS,DH,anon,WITH,RC4,128,MD5,),
-  CS_ENTRY(0x0018, ADH,RC4,MD5,,,,,),
-  CS_ENTRY(0x0019, TLS,DH,anon,EXPORT,WITH,DES40,CBC,SHA),
-  CS_ENTRY(0x0019, EXP,ADH,DES,CBC,SHA,,,),
-  CS_ENTRY(0x001A, TLS,DH,anon,WITH,DES,CBC,SHA,),
-  CS_ENTRY(0x001A, ADH,DES,CBC,SHA,,,,),
-  CS_ENTRY(0x001B, TLS,DH,anon,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0x001B, ADH,DES,CBC3,SHA,,,,),
-  CS_ENTRY(0x0030, TLS,DH,DSS,WITH,AES,128,CBC,SHA),
-  CS_ENTRY(0x0030, DH,DSS,AES128,SHA,,,,),
-  CS_ENTRY(0x0031, TLS,DH,RSA,WITH,AES,128,CBC,SHA),
-  CS_ENTRY(0x0031, DH,RSA,AES128,SHA,,,,),
-  CS_ENTRY(0x0032, TLS,DHE,DSS,WITH,AES,128,CBC,SHA),
-  CS_ENTRY(0x0032, DHE,DSS,AES128,SHA,,,,),
-  CS_ENTRY(0x0034, TLS,DH,anon,WITH,AES,128,CBC,SHA),
-  CS_ENTRY(0x0034, ADH,AES128,SHA,,,,,),
-  CS_ENTRY(0x0036, TLS,DH,DSS,WITH,AES,256,CBC,SHA),
-  CS_ENTRY(0x0036, DH,DSS,AES256,SHA,,,,),
-  CS_ENTRY(0x0037, TLS,DH,RSA,WITH,AES,256,CBC,SHA),
-  CS_ENTRY(0x0037, DH,RSA,AES256,SHA,,,,),
-  CS_ENTRY(0x0038, TLS,DHE,DSS,WITH,AES,256,CBC,SHA),
-  CS_ENTRY(0x0038, DHE,DSS,AES256,SHA,,,,),
-  CS_ENTRY(0x003A, TLS,DH,anon,WITH,AES,256,CBC,SHA),
-  CS_ENTRY(0x003A, ADH,AES256,SHA,,,,,),
-  CS_ENTRY(0x003E, TLS,DH,DSS,WITH,AES,128,CBC,SHA256),
-  CS_ENTRY(0x003E, DH,DSS,AES128,SHA256,,,,),
-  CS_ENTRY(0x003F, TLS,DH,RSA,WITH,AES,128,CBC,SHA256),
-  CS_ENTRY(0x003F, DH,RSA,AES128,SHA256,,,,),
-  CS_ENTRY(0x0040, TLS,DHE,DSS,WITH,AES,128,CBC,SHA256),
-  CS_ENTRY(0x0040, DHE,DSS,AES128,SHA256,,,,),
-  CS_ENTRY(0x0068, TLS,DH,DSS,WITH,AES,256,CBC,SHA256),
-  CS_ENTRY(0x0068, DH,DSS,AES256,SHA256,,,,),
-  CS_ENTRY(0x0069, TLS,DH,RSA,WITH,AES,256,CBC,SHA256),
-  CS_ENTRY(0x0069, DH,RSA,AES256,SHA256,,,,),
-  CS_ENTRY(0x006A, TLS,DHE,DSS,WITH,AES,256,CBC,SHA256),
-  CS_ENTRY(0x006A, DHE,DSS,AES256,SHA256,,,,),
-  CS_ENTRY(0x006C, TLS,DH,anon,WITH,AES,128,CBC,SHA256),
-  CS_ENTRY(0x006C, ADH,AES128,SHA256,,,,,),
-  CS_ENTRY(0x006D, TLS,DH,anon,WITH,AES,256,CBC,SHA256),
-  CS_ENTRY(0x006D, ADH,AES256,SHA256,,,,,),
-  CS_ENTRY(0x008A, TLS,PSK,WITH,RC4,128,SHA,,),
-  CS_ENTRY(0x008A, PSK,RC4,SHA,,,,,),
-  CS_ENTRY(0x008B, TLS,PSK,WITH,3DES,EDE,CBC,SHA,),
-  CS_ENTRY(0x008B, PSK,3DES,EDE,CBC,SHA,,,),
-  CS_ENTRY(0x008E, TLS,DHE,PSK,WITH,RC4,128,SHA,),
-  CS_ENTRY(0x008E, DHE,PSK,RC4,SHA,,,,),
-  CS_ENTRY(0x008F, TLS,DHE,PSK,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0x008F, DHE,PSK,3DES,EDE,CBC,SHA,,),
-  CS_ENTRY(0x0092, TLS,RSA,PSK,WITH,RC4,128,SHA,),
-  CS_ENTRY(0x0092, RSA,PSK,RC4,SHA,,,,),
-  CS_ENTRY(0x0093, TLS,RSA,PSK,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0x0093, RSA,PSK,3DES,EDE,CBC,SHA,,),
-  CS_ENTRY(0x00A0, TLS,DH,RSA,WITH,AES,128,GCM,SHA256),
-  CS_ENTRY(0x00A0, DH,RSA,AES128,GCM,SHA256,,,),
-  CS_ENTRY(0x00A1, TLS,DH,RSA,WITH,AES,256,GCM,SHA384),
-  CS_ENTRY(0x00A1, DH,RSA,AES256,GCM,SHA384,,,),
-  CS_ENTRY(0x00A2, TLS,DHE,DSS,WITH,AES,128,GCM,SHA256),
-  CS_ENTRY(0x00A2, DHE,DSS,AES128,GCM,SHA256,,,),
-  CS_ENTRY(0x00A3, TLS,DHE,DSS,WITH,AES,256,GCM,SHA384),
-  CS_ENTRY(0x00A3, DHE,DSS,AES256,GCM,SHA384,,,),
-  CS_ENTRY(0x00A4, TLS,DH,DSS,WITH,AES,128,GCM,SHA256),
-  CS_ENTRY(0x00A4, DH,DSS,AES128,GCM,SHA256,,,),
-  CS_ENTRY(0x00A5, TLS,DH,DSS,WITH,AES,256,GCM,SHA384),
-  CS_ENTRY(0x00A5, DH,DSS,AES256,GCM,SHA384,,,),
-  CS_ENTRY(0x00A6, TLS,DH,anon,WITH,AES,128,GCM,SHA256),
-  CS_ENTRY(0x00A6, ADH,AES128,GCM,SHA256,,,,),
-  CS_ENTRY(0x00A7, TLS,DH,anon,WITH,AES,256,GCM,SHA384),
-  CS_ENTRY(0x00A7, ADH,AES256,GCM,SHA384,,,,),
-  CS_ENTRY(0xC002, TLS,ECDH,ECDSA,WITH,RC4,128,SHA,),
-  CS_ENTRY(0xC002, ECDH,ECDSA,RC4,SHA,,,,),
-  CS_ENTRY(0xC007, TLS,ECDHE,ECDSA,WITH,RC4,128,SHA,),
-  CS_ENTRY(0xC007, ECDHE,ECDSA,RC4,SHA,,,,),
-  CS_ENTRY(0xC00C, TLS,ECDH,RSA,WITH,RC4,128,SHA,),
-  CS_ENTRY(0xC00C, ECDH,RSA,RC4,SHA,,,,),
-  CS_ENTRY(0xC011, TLS,ECDHE,RSA,WITH,RC4,128,SHA,),
-  CS_ENTRY(0xC011, ECDHE,RSA,RC4,SHA,,,,),
-  CS_ENTRY(0xC015, TLS,ECDH,anon,WITH,NULL,SHA,,),
-  CS_ENTRY(0xC015, AECDH,NULL,SHA,,,,,),
-  CS_ENTRY(0xC016, TLS,ECDH,anon,WITH,RC4,128,SHA,),
-  CS_ENTRY(0xC016, AECDH,RC4,SHA,,,,,),
-  CS_ENTRY(0xC017, TLS,ECDH,anon,WITH,3DES,EDE,CBC,SHA),
-  CS_ENTRY(0xC017, AECDH,DES,CBC3,SHA,,,,),
-  CS_ENTRY(0xC018, TLS,ECDH,anon,WITH,AES,128,CBC,SHA),
-  CS_ENTRY(0xC018, AECDH,AES128,SHA,,,,,),
-  CS_ENTRY(0xC019, TLS,ECDH,anon,WITH,AES,256,CBC,SHA),
-  CS_ENTRY(0xC019, AECDH,AES256,SHA,,,,,),
-#endif
 #if defined(USE_MBEDTLS)
   /* entries marked ns are "non-standard", they are not in OpenSSL */
   CS_ENTRY(0x0041, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA,),
@@ -739,7 +560,7 @@
   size_t len;
 
   /* split the cipher string by '-' or '_' */
-  if(strncasecompare(cs_str, "TLS", 3))
+  if(curl_strnequal(cs_str, "TLS", 3))
     separator = '_';
 
   do {
@@ -754,7 +575,7 @@
     /* lookup index for the part (skip empty string at 0) */
     for(idx = 1, entry = cs_txt + 1; idx < CS_TXT_LEN; idx++) {
       size_t elen = strlen(entry);
-      if(elen == len && strncasecompare(entry, cur, len))
+      if(elen == len && curl_strnequal(entry, cur, len))
         break;
       entry += elen + 1;
     }
@@ -887,5 +708,4 @@
   return r;
 }
 
-#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
-          defined(USE_BEARSSL) || defined(USE_RUSTLS) */
+#endif /* defined(USE_MBEDTLS) || defined(USE_RUSTLS) */
diff --git a/Utilities/cmcurl/lib/vtls/cipher_suite.h b/Utilities/cmcurl/lib/vtls/cipher_suite.h
index cd556db..a1dcbc5 100644
--- a/Utilities/cmcurl/lib/vtls/cipher_suite.h
+++ b/Utilities/cmcurl/lib/vtls/cipher_suite.h
@@ -26,8 +26,7 @@
 
 #include "../curl_setup.h"
 
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
-    defined(USE_BEARSSL) || defined(USE_RUSTLS)
+#if defined(USE_MBEDTLS) || defined(USE_RUSTLS)
 #include <stdint.h>
 
 /* Lookup IANA id for cipher suite string, returns 0 if not recognized */
@@ -43,6 +42,5 @@
 int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
                               bool prefer_rfc);
 
-#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
-          defined(USE_BEARSSL) || defined(USE_RUSTLS) */
+#endif /* defined(USE_MBEDTLS) || defined(USE_RUSTLS) */
 #endif /* HEADER_CURL_CIPHER_SUITE_H */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index 74c36fe..f5e0297 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -53,7 +53,6 @@
 #include "../connect.h" /* for the connect timeout */
 #include "../progress.h"
 #include "../select.h"
-#include "../strcase.h"
 #include "../strdup.h"
 #include "../curlx/warnless.h"
 #include "x509asn1.h"
@@ -91,21 +90,21 @@
   struct gtls_ssl_backend_data *backend =
     (struct gtls_ssl_backend_data *)connssl->backend;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
   DEBUGASSERT(data);
-  nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
-  CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d",
-              blen, nwritten, result);
+  result = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &nwritten);
+  CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %d, %zu",
+              blen, result, nwritten);
   backend->gtls.io_result = result;
-  if(nwritten < 0) {
+  if(result) {
     /* !checksrc! disable ERRNOVAR 1 */
     gnutls_transport_set_errno(backend->gtls.session,
                                (CURLE_AGAIN == result) ? EAGAIN : EINVAL);
-    nwritten = -1;
+    return -1;
   }
-  return nwritten;
+  return (ssize_t)nwritten;
 }
 
 static ssize_t gtls_pull(void *s, void *buf, size_t blen)
@@ -115,7 +114,7 @@
   struct gtls_ssl_backend_data *backend =
     (struct gtls_ssl_backend_data *)connssl->backend;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nread;
+  size_t nread;
   CURLcode result;
 
   DEBUGASSERT(data);
@@ -129,19 +128,19 @@
     }
   }
 
-  nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
-  CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %zd, err=%d",
-              blen, nread, result);
+  result = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread);
+  CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %d, %zd",
+              blen, result, nread);
   backend->gtls.io_result = result;
-  if(nread < 0) {
+  if(result) {
     /* !checksrc! disable ERRNOVAR 1 */
     gnutls_transport_set_errno(backend->gtls.session,
                                (CURLE_AGAIN == result) ? EAGAIN : EINVAL);
-    nread = -1;
+    return -1;
   }
   else if(nread == 0)
     connssl->peer_closed = TRUE;
-  return nread;
+  return (ssize_t)nread;
 }
 
 /* gtls_init()
@@ -303,9 +302,9 @@
 {
   if(!type || !type[0])
     return GNUTLS_X509_FMT_PEM;
-  if(strcasecompare(type, "PEM"))
+  if(curl_strequal(type, "PEM"))
     return GNUTLS_X509_FMT_PEM;
-  if(strcasecompare(type, "DER"))
+  if(curl_strequal(type, "DER"))
     return GNUTLS_X509_FMT_DER;
   return GNUTLS_X509_FMT_PEM; /* default to PEM */
 }
@@ -784,9 +783,9 @@
 }
 
 static CURLcode gtls_set_priority(struct Curl_cfilter *cf,
-                                 struct Curl_easy *data,
-                                 struct gtls_ctx *gtls,
-                                 const char *priority)
+                                  struct Curl_easy *data,
+                                  struct gtls_ctx *gtls,
+                                  const char *priority)
 {
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
   struct dynbuf buf;
@@ -982,7 +981,7 @@
       if(result)
         return result;
     }
-    if(ssl_config->cert_type && strcasecompare(ssl_config->cert_type, "P12")) {
+    if(ssl_config->cert_type && curl_strequal(ssl_config->cert_type, "P12")) {
       rc = gnutls_certificate_set_x509_simple_pkcs12_file(
         gtls->shared_creds->creds, config->clientcert, GNUTLS_X509_FMT_DER,
         ssl_config->key_passwd ? ssl_config->key_passwd : "");
@@ -1080,7 +1079,7 @@
   connssl->earlydata_max =
     gnutls_record_get_max_early_data_size(backend->gtls.session);
   if((!connssl->earlydata_max || connssl->earlydata_max == 0xFFFFFFFFUL)) {
-    /* Seems to be GnuTLS way to signal no EarlyData in session */
+    /* Seems to be no GnuTLS way to signal no EarlyData in session */
     CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
   }
   else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
@@ -1308,6 +1307,28 @@
   return result;
 }
 
+void Curl_gtls_report_handshake(struct Curl_easy *data,
+                                struct gtls_ctx *gctx)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(Curl_trc_is_verbose(data)) {
+    const char *ptr;
+    gnutls_protocol_t version = gnutls_protocol_get_version(gctx->session);
+
+    /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
+    ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(gctx->session),
+                                       gnutls_cipher_get(gctx->session),
+                                       gnutls_mac_get(gctx->session));
+
+    infof(data, "SSL connection using %s / %s",
+          gnutls_protocol_get_name(version), ptr);
+  }
+#else
+  (void)data;
+  (void)gctx;
+#endif
+}
+
 CURLcode
 Curl_gtls_verifyserver(struct Curl_easy *data,
                        gnutls_session_t session,
@@ -1328,23 +1349,11 @@
   int rc;
   CURLcode result = CURLE_OK;
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-  const char *ptr;
   int algo;
   unsigned int bits;
-  gnutls_protocol_t version = gnutls_protocol_get_version(session);
 #endif
   long * const certverifyresult = &ssl_config->certverifyresult;
 
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-  /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
-  ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
-                                     gnutls_cipher_get(session),
-                                     gnutls_mac_get(session));
-
-  infof(data, "SSL connection using %s / %s",
-        gnutls_protocol_get_name(version), ptr);
-#endif
-
   /* This function will return the peer's raw certificate (chain) as sent by
      the peer. These certificates are in raw format (DER encoded for
      X.509). In case of a X.509 then a certificate list may be present. The
@@ -1877,6 +1886,9 @@
   if(connssl->connecting_state == ssl_connect_3) {
     gnutls_datum_t proto;
     int rc;
+
+    Curl_gtls_report_handshake(data, &backend->gtls);
+
     result = gtls_verifyserver(cf, data, backend->gtls.session);
     if(result)
       goto out;
@@ -1948,48 +1960,49 @@
   return FALSE;
 }
 
-static ssize_t gtls_send(struct Curl_cfilter *cf,
-                         struct Curl_easy *data,
-                         const void *buf,
-                         size_t blen,
-                         CURLcode *curlcode)
+static CURLcode gtls_send(struct Curl_cfilter *cf,
+                          struct Curl_easy *data,
+                          const void *buf,
+                          size_t blen,
+                          size_t *pnwritten)
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct gtls_ssl_backend_data *backend =
     (struct gtls_ssl_backend_data *)connssl->backend;
-  ssize_t rc;
-  size_t nwritten, total_written = 0;
+  CURLcode result = CURLE_OK;
+  ssize_t nwritten;
+  size_t remain = blen;
 
   (void)data;
   DEBUGASSERT(backend);
+  *pnwritten = 0;
 
-  while(blen) {
+  while(remain) {
     backend->gtls.io_result = CURLE_OK;
-    rc = gnutls_record_send(backend->gtls.session, buf, blen);
+    nwritten = gnutls_record_send(backend->gtls.session, buf, remain);
 
-    if(rc < 0) {
-      if(total_written && (rc == GNUTLS_E_AGAIN)) {
-        *curlcode = CURLE_OK;
-        rc = (ssize_t)total_written;
+    if(nwritten >= 0) {
+      *pnwritten += (size_t)nwritten;
+      DEBUGASSERT((size_t)nwritten <= remain);
+      buf = (char *)CURL_UNCONST(buf) + (size_t)nwritten;
+      remain -= (size_t)nwritten;
+    }
+    else {
+      if(*pnwritten && (nwritten == GNUTLS_E_AGAIN)) {
+        result = CURLE_OK;
         goto out;
       }
-      *curlcode = (rc == GNUTLS_E_AGAIN) ?
+      result = (nwritten == GNUTLS_E_AGAIN) ?
         CURLE_AGAIN :
         (backend->gtls.io_result ? backend->gtls.io_result : CURLE_SEND_ERROR);
-
-      rc = -1;
       goto out;
     }
-    nwritten = (size_t)rc;
-    total_written += nwritten;
-    DEBUGASSERT(nwritten <= blen);
-    buf = (char *)CURL_UNCONST(buf) + nwritten;
-    blen -= nwritten;
   }
-  rc = total_written;
 
 out:
-  return rc;
+  CURL_TRC_CF(data, cf, "gtls_send(len=%zu) -> %d, %zu",
+              blen, result, *pnwritten);
+  return result;
 }
 
 /*
@@ -2095,50 +2108,49 @@
 #endif
 }
 
-static ssize_t gtls_recv(struct Curl_cfilter *cf,
-                         struct Curl_easy *data,
-                         char *buf,
-                         size_t buffersize,
-                         CURLcode *curlcode)
+static CURLcode gtls_recv(struct Curl_cfilter *cf,
+                          struct Curl_easy *data,
+                          char *buf, size_t blen,
+                          size_t *pnread)
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct gtls_ssl_backend_data *backend =
     (struct gtls_ssl_backend_data *)connssl->backend;
-  ssize_t ret;
+  CURLcode result = CURLE_OK;
+  ssize_t nread;
 
   (void)data;
   DEBUGASSERT(backend);
 
-  ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
-  if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
-    *curlcode = CURLE_AGAIN;
-    ret = -1;
-    goto out;
-  }
+  nread = gnutls_record_recv(backend->gtls.session, buf, blen);
 
-  if(ret == GNUTLS_E_REHANDSHAKE) {
-    /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
-       proper way" takes a whole lot of work. */
-    CURLcode result = handshake(cf, data);
-    if(result)
-      *curlcode = result;
-    else
-      *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
-    ret = -1;
-    goto out;
-  }
-
-  if(ret < 0) {
-    failf(data, "GnuTLS recv error (%d): %s",
-          (int)ret, gnutls_strerror((int)ret));
-    *curlcode = backend->gtls.io_result ?
-      backend->gtls.io_result : CURLE_RECV_ERROR;
-    ret = -1;
-    goto out;
+  if(nread >= 0)
+    *pnread = (size_t)nread;
+  else {
+    if((nread == GNUTLS_E_AGAIN) || (nread == GNUTLS_E_INTERRUPTED)) {
+      result = CURLE_AGAIN;
+      goto out;
+    }
+    else if(nread == GNUTLS_E_REHANDSHAKE) {
+      /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
+         proper way" takes a whole lot of work. */
+      result = handshake(cf, data);
+      if(!result)
+        result = CURLE_AGAIN; /* then return as if this was a wouldblock */
+      goto out;
+    }
+    else {
+      failf(data, "GnuTLS recv error (%d): %s",
+            (int)nread, gnutls_strerror((int)nread));
+      result = backend->gtls.io_result ?
+        backend->gtls.io_result : CURLE_RECV_ERROR;
+      goto out;
+    }
   }
 
 out:
-  return ret;
+  CURL_TRC_CF(data, cf, "gtls_recv(len=%zu) -> 0, %zu", blen, *pnread);
+  return result;
 }
 
 size_t Curl_gtls_version(char *buffer, size_t size)
@@ -2210,7 +2222,6 @@
   NULL,                          /* set_engine */
   NULL,                          /* set_engine_default */
   NULL,                          /* engines_list */
-  NULL,                          /* false_start */
   gtls_sha256sum,                /* sha256sum */
   gtls_recv,                     /* recv decrypted data */
   gtls_send,                     /* send data to encrypt */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
index 35af9db..01f8b43 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.h
+++ b/Utilities/cmcurl/lib/vtls/gtls.h
@@ -117,6 +117,10 @@
                                  unsigned char *quic_tp,
                                  size_t quic_tp_len);
 
+/* Report properties of a successful handshake */
+void Curl_gtls_report_handshake(struct Curl_easy *data,
+                                struct gtls_ctx *gctx);
+
 extern const struct Curl_ssl Curl_ssl_gnutls;
 
 #endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/lib/vtls/hostcheck.c b/Utilities/cmcurl/lib/vtls/hostcheck.c
index 8ca6994..68af9be 100644
--- a/Utilities/cmcurl/lib/vtls/hostcheck.c
+++ b/Utilities/cmcurl/lib/vtls/hostcheck.c
@@ -36,7 +36,6 @@
 #endif
 #include "../curl_memrchr.h"
 #include "hostcheck.h"
-#include "../strcase.h"
 #include "../hostip.h"
 
 #include "../curl_memory.h"
@@ -50,7 +49,7 @@
 {
   if(hostlen != patternlen)
     return FALSE;
-  return strncasecompare(hostname, pattern, hostlen);
+  return curl_strnequal(hostname, pattern, hostlen);
 }
 
 /*
diff --git a/Utilities/cmcurl/lib/vtls/keylog.c b/Utilities/cmcurl/lib/vtls/keylog.c
index 8487d43..2fd2508 100644
--- a/Utilities/cmcurl/lib/vtls/keylog.c
+++ b/Utilities/cmcurl/lib/vtls/keylog.c
@@ -134,14 +134,14 @@
 
   /* Client Random */
   for(i = 0; i < CLIENT_RANDOM_SIZE; i++) {
-    Curl_hexbyte(&line[pos], client_random[i], FALSE);
+    Curl_hexbyte(&line[pos], client_random[i]);
     pos += 2;
   }
   line[pos++] = ' ';
 
   /* Secret */
   for(i = 0; i < secretlen; i++) {
-    Curl_hexbyte(&line[pos], secret[i], FALSE);
+    Curl_hexbyte(&line[pos], secret[i]);
     pos += 2;
   }
   line[pos++] = '\n';
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index 7af207c..75190d3 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -57,7 +57,6 @@
 #endif /* MBEDTLS_VERSION_MAJOR >= 2 */
 
 #include "cipher_suite.h"
-#include "../strcase.h"
 #include "../urldata.h"
 #include "../sendf.h"
 #include "../curlx/inet_pton.h"
@@ -191,28 +190,27 @@
 {
   struct Curl_cfilter *cf = bio;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
   DEBUGASSERT(data);
   if(!data)
     return 0;
 
-  nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, blen, FALSE,
-                               &result);
-  CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d",
-              blen, nwritten, result);
-  if(nwritten < 0 && CURLE_AGAIN == result) {
-    nwritten = MBEDTLS_ERR_SSL_WANT_WRITE;
-  }
-  return (int)nwritten;
+  result = Curl_conn_cf_send(cf->next, data, (const char *)buf, blen, FALSE,
+                             &nwritten);
+  CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %d, %zu",
+              blen, result, nwritten);
+  if(CURLE_AGAIN == result)
+    return MBEDTLS_ERR_SSL_WANT_WRITE;
+  return result ? -1 : (int)nwritten;
 }
 
 static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen)
 {
   struct Curl_cfilter *cf = bio;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nread;
+  size_t nread;
   CURLcode result;
 
   DEBUGASSERT(data);
@@ -222,13 +220,12 @@
   if(!buf)
     return 0;
 
-  nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result);
-  CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %zd, err=%d",
-              blen, nread, result);
-  if(nread < 0 && CURLE_AGAIN == result) {
-    nread = MBEDTLS_ERR_SSL_WANT_READ;
-  }
-  return (int)nread;
+  result = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &nread);
+  CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %d, %zu",
+              blen, result, nread);
+  if(CURLE_AGAIN == result)
+    return MBEDTLS_ERR_SSL_WANT_READ;
+  return result ? -1 : (int)nread;
 }
 
 /*
@@ -384,7 +381,7 @@
   size_t len = *end - *str;
 
   if(!id) {
-    if(strncasecompare("TLS_ECJPAKE_WITH_AES_128_CCM_8", *str, len))
+    if(curl_strnequal("TLS_ECJPAKE_WITH_AES_128_CCM_8", *str, len))
       id = MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8;
   }
   return id;
@@ -1205,16 +1202,18 @@
   return result;
 }
 
-static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-                         const void *mem, size_t len,
-                         CURLcode *curlcode)
+static CURLcode mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          const void *mem, size_t len,
+                          size_t *pnwritten)
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct mbed_ssl_backend_data *backend =
     (struct mbed_ssl_backend_data *)connssl->backend;
-  int ret = -1;
+  CURLcode result = CURLE_OK;
+  int nwritten;
 
   (void)data;
+  *pnwritten = 0;
   DEBUGASSERT(backend);
   /* mbedtls is picky when a mbedtls_ssl_write) was previously blocked.
    * It requires to be called with the same amount of bytes again, or it
@@ -1227,28 +1226,29 @@
     len = backend->send_blocked_len;
   }
 
-  ret = mbedtls_ssl_write(&backend->ssl, (const unsigned char *)mem, len);
+  nwritten = mbedtls_ssl_write(&backend->ssl, (const unsigned char *)mem, len);
 
-  if(ret < 0) {
+  if(nwritten >= 0) {
+    *pnwritten = (size_t)nwritten;
+    backend->send_blocked = FALSE;
+  }
+  else {
     CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X",
-                len, -ret);
-    *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_WRITE)
+                len, -nwritten);
+    result = ((nwritten == MBEDTLS_ERR_SSL_WANT_WRITE)
 #ifdef HAS_TLS13_SUPPORT
-      || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
+      || (nwritten == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
 #endif
       ) ? CURLE_AGAIN : CURLE_SEND_ERROR;
-    ret = -1;
-    if((*curlcode == CURLE_AGAIN) && !backend->send_blocked) {
+    if((result == CURLE_AGAIN) && !backend->send_blocked) {
       backend->send_blocked = TRUE;
       backend->send_blocked_len = len;
     }
   }
-  else {
-    CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d", len, ret);
-    backend->send_blocked = FALSE;
-  }
 
-  return ret;
+  CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d, %zu",
+              len, result, *pnwritten);
+  return result;
 }
 
 static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf,
@@ -1367,48 +1367,48 @@
   }
 }
 
-static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-                         char *buf, size_t buffersize,
-                         CURLcode *curlcode)
+static CURLcode mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
+                          char *buf, size_t buffersize,
+                          size_t *pnread)
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct mbed_ssl_backend_data *backend =
     (struct mbed_ssl_backend_data *)connssl->backend;
-  int ret = -1;
+  CURLcode result = CURLE_OK;
+  int nread;
 
   (void)data;
   DEBUGASSERT(backend);
+  *pnread = 0;
 
-  ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
-                         buffersize);
-  if(ret <= 0) {
+  nread = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, buffersize);
+  if(nread > 0)
+    *pnread = (size_t)nread;
+  else {
     CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
-                buffersize, -ret);
-    switch(ret) {
+                buffersize, -nread);
+    switch(nread) {
 #ifdef HAS_SESSION_TICKETS
     case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET:
       mbed_new_session(cf, data);
       FALLTHROUGH();
 #endif
     case MBEDTLS_ERR_SSL_WANT_READ:
-      *curlcode = CURLE_AGAIN;
-      ret = -1;
+      result = CURLE_AGAIN;
       break;
     case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
-      *curlcode = CURLE_OK;
-      ret = 0;
+      result = CURLE_OK;
       break;
     default: {
       char errorbuf[128];
-      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-      failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
-      *curlcode = CURLE_RECV_ERROR;
-      ret = -1;
+      mbedtls_strerror(nread, errorbuf, sizeof(errorbuf));
+      failf(data, "ssl_read returned: (-0x%04X) %s", -nread, errorbuf);
+      result = CURLE_RECV_ERROR;
       break;
     }
     }
   }
-  return (ssize_t)ret;
+  return result;
 }
 
 static size_t mbedtls_version(char *buffer, size_t size)
@@ -1620,7 +1620,6 @@
   NULL,                             /* set_engine */
   NULL,                             /* set_engine_default */
   NULL,                             /* engines_list */
-  NULL,                             /* false_start */
   mbedtls_sha256sum,                /* sha256sum */
   mbed_recv,                        /* recv decrypted data */
   mbed_send,                        /* send data to encrypt */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 76919b6..32ff317 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -54,12 +54,12 @@
 #include "../connect.h"
 #include "../slist.h"
 #include "../select.h"
+#include "../curlx/wait.h"
 #include "vtls.h"
 #include "vtls_int.h"
 #include "vtls_scache.h"
 #include "../vauth/vauth.h"
 #include "keylog.h"
-#include "../strcase.h"
 #include "hostcheck.h"
 #include "../multiif.h"
 #include "../curlx/strparse.h"
@@ -122,6 +122,12 @@
 static void ossl_provider_cleanup(struct Curl_easy *data);
 #endif
 
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+     !defined(LIBRESSL_VERSION_NUMBER) && \
+     !defined(OPENSSL_IS_BORINGSSL))
+  #define HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN 1
+#endif
+
 #include "../curlx/warnless.h"
 
 /* The last #include files should be: */
@@ -728,22 +734,23 @@
   struct ssl_connect_data *connssl = cf->ctx;
   struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten;
-  CURLcode result = CURLE_SEND_ERROR;
+  size_t nwritten;
+  CURLcode result;
 
   DEBUGASSERT(data);
   if(blen < 0)
     return 0;
 
-  nwritten = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, FALSE,
-                               &result);
-  CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
-              blen, (int)nwritten, result);
+  result = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, FALSE,
+                             &nwritten);
+  CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, %zu",
+              blen, result, nwritten);
   BIO_clear_retry_flags(bio);
   octx->io_result = result;
-  if(nwritten < 0) {
+  if(result) {
     if(CURLE_AGAIN == result)
       BIO_set_retry_write(bio);
+    return -1;
   }
   return (int)nwritten;
 }
@@ -754,8 +761,8 @@
   struct ssl_connect_data *connssl = cf->ctx;
   struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nread;
-  CURLcode result = CURLE_RECV_ERROR;
+  size_t nread;
+  CURLcode result, r2;
 
   DEBUGASSERT(data);
   /* OpenSSL catches this case, so should we. */
@@ -764,31 +771,33 @@
   if(blen < 0)
     return 0;
 
-  nread = Curl_conn_cf_recv(cf->next, data, buf, (size_t)blen, &result);
-  CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d",
-              blen, (int)nread, result);
+  result = Curl_conn_cf_recv(cf->next, data, buf, (size_t)blen, &nread);
+  CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, %zu",
+              blen, result, nread);
   BIO_clear_retry_flags(bio);
   octx->io_result = result;
-  if(nread < 0) {
+  if(result) {
     if(CURLE_AGAIN == result)
       BIO_set_retry_read(bio);
   }
-  else if(nread == 0) {
-    connssl->peer_closed = TRUE;
+  else {
+    /* feeding data to OpenSSL means SSL_read() might succeed */
+    connssl->input_pending = TRUE;
+    if(nread == 0)
+      connssl->peer_closed = TRUE;
   }
 
   /* Before returning server replies to the SSL instance, we need
    * to have setup the x509 store or verification will fail. */
   if(!octx->x509_store_setup) {
-    result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
-    if(result) {
-      octx->io_result = result;
+    r2 = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
+    if(r2) {
+      octx->io_result = r2;
       return -1;
     }
     octx->x509_store_setup = TRUE;
   }
-
-  return (int)nread;
+  return result ? -1 : (int)nread;
 }
 
 #if OPENSSL_VERSION_NUMBER < 0x10100000L
@@ -1006,7 +1015,7 @@
     size_t i, i_max;
     for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
       struct curltime tv = curlx_now();
-      Curl_wait_ms(1);
+      curlx_wait_ms(1);
       tv.tv_sec *= (time_t)i + 1;
       tv.tv_usec *= (int)i + 2;
       tv.tv_sec ^= ((curlx_now().tv_sec + (time_t)curlx_now().tv_usec) *
@@ -1059,15 +1068,15 @@
 {
   if(!type || !type[0])
     return SSL_FILETYPE_PEM;
-  if(strcasecompare(type, "PEM"))
+  if(curl_strequal(type, "PEM"))
     return SSL_FILETYPE_PEM;
-  if(strcasecompare(type, "DER"))
+  if(curl_strequal(type, "DER"))
     return SSL_FILETYPE_ASN1;
-  if(strcasecompare(type, "PROV"))
+  if(curl_strequal(type, "PROV"))
     return SSL_FILETYPE_PROVIDER;
-  if(strcasecompare(type, "ENG"))
+  if(curl_strequal(type, "ENG"))
     return SSL_FILETYPE_ENGINE;
-  if(strcasecompare(type, "P12"))
+  if(curl_strequal(type, "P12"))
     return SSL_FILETYPE_PKCS12;
   return -1;
 }
@@ -1120,7 +1129,7 @@
  */
 static bool is_pkcs11_uri(const char *string)
 {
-  return string && strncasecompare(string, "pkcs11:", 7);
+  return string && curl_strnequal(string, "pkcs11:", 7);
 }
 
 #endif
@@ -1386,7 +1395,7 @@
     {
       /* Implicitly use pkcs11 provider if none was provided and the
        * cert_file is a PKCS#11 URI */
-      if(!data->state.provider) {
+      if(!data->state.provider_loaded) {
         if(is_pkcs11_uri(cert_file)) {
           if(ossl_set_provider(data, "pkcs11") != CURLE_OK) {
             return 0;
@@ -1394,7 +1403,7 @@
         }
       }
 
-      if(data->state.provider) {
+      if(data->state.provider_loaded) {
         /* Load the certificate from the provider */
         OSSL_STORE_INFO *info = NULL;
         X509 *cert = NULL;
@@ -1639,7 +1648,7 @@
     {
       /* Implicitly use pkcs11 provider if none was provided and the
        * key_file is a PKCS#11 URI */
-      if(!data->state.provider) {
+      if(!data->state.provider_loaded) {
         if(is_pkcs11_uri(key_file)) {
           if(ossl_set_provider(data, "pkcs11") != CURLE_OK) {
             return 0;
@@ -1647,7 +1656,7 @@
         }
       }
 
-      if(data->state.provider) {
+      if(data->state.provider_loaded) {
         /* Load the private key from the provider */
         EVP_PKEY *priv_key = NULL;
         OSSL_STORE_CTX *store = NULL;
@@ -1909,6 +1918,9 @@
       result = CURLE_SSL_ENGINE_INITFAILED;
       e = NULL;
     }
+    else {
+      result = CURLE_OK;
+    }
     data->state.engine = e;
     return result;
   }
@@ -2030,6 +2042,14 @@
     data->state.libctx = libctx;
   }
 
+#ifndef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
+  /* load the configuration file into the library context before checking the
+   * provider availability */
+  if(!OSSL_LIB_CTX_load_config(data->state.libctx, NULL)) {
+    infof(data, "Failed to load default openssl config. Proceeding.");
+  }
+#endif
+
   if(OSSL_PROVIDER_available(data->state.libctx, name)) {
     /* already loaded through the configuration - no action needed */
     data->state.provider_loaded = TRUE;
@@ -2175,6 +2195,8 @@
 
 out:
   cf->shutdown = (result || *done);
+  if(cf->shutdown || (connssl->io_need != CURL_SSL_IO_NEED_NONE))
+    connssl->input_pending = FALSE;
   return result;
 }
 
@@ -2186,6 +2208,7 @@
   (void)data;
   DEBUGASSERT(octx);
 
+  connssl->input_pending = FALSE;
   if(octx->ssl) {
     SSL_free(octx->ssl);
     octx->ssl = NULL;
@@ -2864,8 +2887,8 @@
   long curl_ssl_version_max;
 
   /* convert curl min SSL version option to OpenSSL constant */
-#if (defined(OPENSSL_IS_BORINGSSL)  || \
-     defined(OPENSSL_IS_AWSLC)      || \
+#if (defined(OPENSSL_IS_BORINGSSL) || \
+     defined(OPENSSL_IS_AWSLC) || \
      defined(LIBRESSL_VERSION_NUMBER))
   uint16_t ossl_ssl_version_min = 0;
   uint16_t ossl_ssl_version_max = 0;
@@ -4131,6 +4154,21 @@
   }
 
   SSL_CTX_set_options(octx->ssl_ctx, ctx_options);
+  SSL_CTX_set_read_ahead(octx->ssl_ctx, 1);
+
+  /* Max TLS1.2 record size 0x4000 + 0x800.
+     OpenSSL supports processing "jumbo TLS record" (8 TLS records) in one go
+     for some algorithms, so match that here.
+     Experimentation shows that a slightly larger buffer is needed
+      to avoid short reads.
+
+     However using a large buffer (8 packets) actually decreases performance.
+     4 packets is better.
+   */
+
+#ifdef HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN
+  SSL_CTX_set_default_read_buffer_len(octx->ssl_ctx, 0x401e * 4);
+#endif
 
 #ifdef SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
   /* We do retry writes sometimes from another buffer address */
@@ -4315,6 +4353,38 @@
   return result;
 }
 
+void Curl_ossl_report_handshake(struct Curl_easy *data,
+                                struct ossl_ctx *octx)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(Curl_trc_is_verbose(data)) {
+    int psigtype_nid = NID_undef;
+    const char *negotiated_group_name = NULL;
+
+#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
+    SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid);
+#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
+    negotiated_group_name = SSL_get0_group_name(octx->ssl);
+#else
+    negotiated_group_name =
+      OBJ_nid2sn(SSL_get_negotiated_group(octx->ssl) & 0x0000FFFF);
+#endif
+#endif
+
+    /* Informational message */
+    infof(data, "SSL connection using %s / %s / %s / %s",
+          SSL_get_version(octx->ssl),
+          SSL_get_cipher(octx->ssl),
+          negotiated_group_name ? negotiated_group_name : "[blank]",
+          OBJ_nid2sn(psigtype_nid));
+  }
+#else
+  (void)data;
+  (void)octx;
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+
+}
+
 static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
                                    struct Curl_easy *data)
 {
@@ -4580,28 +4650,9 @@
     }
   }
   else {
-    int psigtype_nid = NID_undef;
-    const char *negotiated_group_name = NULL;
-
     /* we connected fine, we are not waiting for anything else. */
     connssl->connecting_state = ssl_connect_3;
-
-#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
-    SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid);
-#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
-    negotiated_group_name = SSL_get0_group_name(octx->ssl);
-#else
-    negotiated_group_name =
-      OBJ_nid2sn(SSL_get_negotiated_group(octx->ssl) & 0x0000FFFF);
-#endif
-#endif
-
-    /* Informational message */
-    infof(data, "SSL connection using %s / %s / %s / %s",
-          SSL_get_version(octx->ssl),
-          SSL_get_cipher(octx->ssl),
-          negotiated_group_name ? negotiated_group_name : "[blank]",
-          OBJ_nid2sn(psigtype_nid));
+    Curl_ossl_report_handshake(data, octx);
 
 #ifdef USE_ECH_OPENSSL
 # if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
@@ -4658,10 +4709,10 @@
         infof(data, "ECH: ech-hard failed");
         return CURLE_SSL_CONNECT_ERROR;
       }
-   }
-   else {
+    }
+    else {
       infof(data, "ECH: result: status is not attempted");
-   }
+    }
 # endif  /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
 #endif  /* USE_ECH_OPENSSL */
 
@@ -5214,20 +5265,15 @@
                               const struct Curl_easy *data)
 {
   struct ssl_connect_data *connssl = cf->ctx;
-  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
-
   (void)data;
-  DEBUGASSERT(connssl && octx);
-  if(octx->ssl && SSL_pending(octx->ssl))
-    return TRUE;
-  return FALSE;
+  return connssl->input_pending;
 }
 
-static ssize_t ossl_send(struct Curl_cfilter *cf,
-                         struct Curl_easy *data,
-                         const void *mem,
-                         size_t len,
-                         CURLcode *curlcode)
+static CURLcode ossl_send(struct Curl_cfilter *cf,
+                          struct Curl_easy *data,
+                          const void *mem,
+                          size_t len,
+                          size_t *pnwritten)
 {
   /* SSL_write() is said to return 'int' while write() and send() returns
      'size_t' */
@@ -5235,39 +5281,39 @@
   char error_buffer[256];
   sslerr_t sslerror;
   int memlen;
-  int rc;
   struct ssl_connect_data *connssl = cf->ctx;
   struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+  CURLcode result = CURLE_OK;
+  int nwritten;
 
   (void)data;
   DEBUGASSERT(octx);
-
+  *pnwritten = 0;
   ERR_clear_error();
 
   connssl->io_need = CURL_SSL_IO_NEED_NONE;
   memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
-  rc = SSL_write(octx->ssl, mem, memlen);
+  nwritten = SSL_write(octx->ssl, mem, memlen);
 
-  if(rc <= 0) {
-    err = SSL_get_error(octx->ssl, rc);
+  if(nwritten > 0)
+    *pnwritten = (size_t)nwritten;
+  else {
+    err = SSL_get_error(octx->ssl, nwritten);
 
     switch(err) {
     case SSL_ERROR_WANT_READ:
       connssl->io_need = CURL_SSL_IO_NEED_RECV;
-      *curlcode = CURLE_AGAIN;
-      rc = -1;
+      result = CURLE_AGAIN;
       goto out;
     case SSL_ERROR_WANT_WRITE:
-      *curlcode = CURLE_AGAIN;
-      rc = -1;
+      result = CURLE_AGAIN;
       goto out;
     case SSL_ERROR_SYSCALL:
     {
       int sockerr = SOCKERRNO;
 
       if(octx->io_result == CURLE_AGAIN) {
-        *curlcode = CURLE_AGAIN;
-        rc = -1;
+        result = CURLE_AGAIN;
         goto out;
       }
       sslerror = ERR_get_error();
@@ -5281,8 +5327,7 @@
 
       failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
             error_buffer, sockerr);
-      *curlcode = CURLE_SEND_ERROR;
-      rc = -1;
+      result = CURLE_SEND_ERROR;
       goto out;
     }
     case SSL_ERROR_SSL: {
@@ -5291,49 +5336,50 @@
       sslerror = ERR_get_error();
       failf(data, "SSL_write() error: %s",
             ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
-      *curlcode = CURLE_SEND_ERROR;
-      rc = -1;
+      result = CURLE_SEND_ERROR;
       goto out;
     }
     default:
       /* a true error */
       failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
             SSL_ERROR_to_str(err), SOCKERRNO);
-      *curlcode = CURLE_SEND_ERROR;
-      rc = -1;
+      result = CURLE_SEND_ERROR;
       goto out;
     }
   }
-  *curlcode = CURLE_OK;
 
 out:
-  return (ssize_t)rc; /* number of bytes */
+  return result;
 }
 
-static ssize_t ossl_recv(struct Curl_cfilter *cf,
-                         struct Curl_easy *data,   /* transfer */
-                         char *buf,                /* store read data here */
-                         size_t buffersize,        /* max amount to read */
-                         CURLcode *curlcode)
+static CURLcode ossl_recv(struct Curl_cfilter *cf,
+                          struct Curl_easy *data,   /* transfer */
+                          char *buf,                /* store read data here */
+                          size_t buffersize,        /* max amount to read */
+                          size_t *pnread)
 {
   char error_buffer[256];
   unsigned long sslerror;
-  ssize_t nread;
   int buffsize;
   struct connectdata *conn = cf->conn;
   struct ssl_connect_data *connssl = cf->ctx;
   struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+  CURLcode result = CURLE_OK;
+  int nread;
 
   (void)data;
   DEBUGASSERT(octx);
 
+  *pnread = 0;
   ERR_clear_error();
 
   connssl->io_need = CURL_SSL_IO_NEED_NONE;
   buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
-  nread = (ssize_t)SSL_read(octx->ssl, buf, buffsize);
+  nread = SSL_read(octx->ssl, buf, buffsize);
 
-  if(nread <= 0) {
+  if(nread > 0)
+    *pnread = (size_t)nread;
+  else {
     /* failed SSL_read */
     int err = SSL_get_error(octx->ssl, (int)nread);
 
@@ -5348,21 +5394,18 @@
         connclose(conn, "TLS close_notify");
       break;
     case SSL_ERROR_WANT_READ:
-      *curlcode = CURLE_AGAIN;
-      nread = -1;
+      result = CURLE_AGAIN;
       goto out;
     case SSL_ERROR_WANT_WRITE:
       connssl->io_need = CURL_SSL_IO_NEED_SEND;
-      *curlcode = CURLE_AGAIN;
-      nread = -1;
+      result = CURLE_AGAIN;
       goto out;
     default:
       /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
          value/errno" */
       /* https://docs.openssl.org/master/man3/ERR_get_error/ */
       if(octx->io_result == CURLE_AGAIN) {
-        *curlcode = CURLE_AGAIN;
-        nread = -1;
+        result = CURLE_AGAIN;
         goto out;
       }
       sslerror = ERR_get_error();
@@ -5379,40 +5422,50 @@
                     SSL_ERROR_to_str(err));
         failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
               error_buffer, sockerr);
-        *curlcode = CURLE_RECV_ERROR;
-        nread = -1;
+        result = CURLE_RECV_ERROR;
         goto out;
       }
-      /* For debug builds be a little stricter and error on any
-         SSL_ERROR_SYSCALL. For example a server may have closed the connection
-         abruptly without a close_notify alert. For compatibility with older
-         peers we do not do this by default. #4624
-
-         We can use this to gauge how many users may be affected, and
-         if it goes ok eventually transition to allow in dev and release with
-         the newest OpenSSL: #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) */
-#ifdef DEBUGBUILD
-      if(err == SSL_ERROR_SYSCALL) {
-        int sockerr = SOCKERRNO;
-        if(sockerr)
-          Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
-        else {
-          msnprintf(error_buffer, sizeof(error_buffer),
-                    "Connection closed abruptly");
+      else if(err == SSL_ERROR_SYSCALL) {
+        if(octx->io_result) {
+          /* logging handling in underlying filter already */
+          result = octx->io_result;
         }
-        failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d"
-              " (Fatal because this is a curl debug build)",
-              error_buffer, sockerr);
-        *curlcode = CURLE_RECV_ERROR;
-        nread = -1;
+        else if(connssl->peer_closed) {
+          failf(data, "Connection closed abruptly");
+          result = CURLE_RECV_ERROR;
+        }
+        else {
+          /* We should no longer get here nowadays. But handle
+           * the error in case of some weirdness in the OSSL stack */
+          int sockerr = SOCKERRNO;
+          if(sockerr)
+            Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+          else {
+            msnprintf(error_buffer, sizeof(error_buffer),
+                      "Connection closed abruptly");
+          }
+          failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
+                error_buffer, sockerr);
+          result = CURLE_RECV_ERROR;
+        }
         goto out;
       }
-#endif
     }
   }
 
 out:
-  return nread;
+  if((!result && !*pnread) || (result == CURLE_AGAIN)) {
+    /* This happens when:
+     * - we read an EOF
+     * - OpenSSLs buffers are empty, there is no more data
+     * - OpenSSL read is blocked on writing something first
+     * - an incomplete TLS packet is buffered that cannot be read
+     *   until more data arrives */
+    connssl->input_pending = FALSE;
+  }
+  CURL_TRC_CF(data, cf, "ossl_recv(len=%zu) -> %d, %zu (in_pending=%d)",
+              buffersize, result, *pnread, connssl->input_pending);
+  return result;
 }
 
 static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex,
@@ -5506,7 +5559,7 @@
   size_t count;
   const char *ver = OpenSSL_version(OPENSSL_VERSION);
   const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
-  if(strncasecompare(ver, expected, sizeof(expected) - 1)) {
+  if(curl_strnequal(ver, expected, sizeof(expected) - 1)) {
     ver += sizeof(expected) - 1;
   }
   count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver);
@@ -5664,7 +5717,6 @@
   ossl_set_engine,          /* set_engine or provider */
   ossl_set_engine_default,  /* set_engine_default */
   ossl_engines_list,        /* engines_list */
-  NULL,                     /* false_start */
 #ifndef OPENSSL_NO_SHA256
   ossl_sha256sum,           /* sha256sum */
 #else
diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h
index 8d063e2..1338eaf 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.h
+++ b/Utilities/cmcurl/lib/vtls/openssl.h
@@ -142,5 +142,9 @@
                                   struct ossl_ctx *octx,
                                   struct ssl_peer *peer);
 
+/* Report properties of a successful handshake */
+void Curl_ossl_report_handshake(struct Curl_easy *data,
+                                struct ossl_ctx *octx);
+
 #endif /* USE_OPENSSL */
 #endif /* HEADER_CURL_SSLUSE_H */
diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c
index cb9fd62..4e1b78a 100644
--- a/Utilities/cmcurl/lib/vtls/rustls.c
+++ b/Utilities/cmcurl/lib/vtls/rustls.c
@@ -43,6 +43,10 @@
 #include "cipher_suite.h"
 #include "x509asn1.h"
 
+/* The last #include files should be: */
+#include "../curl_memory.h"
+#include "../memdebug.h"
+
 struct rustls_ssl_backend_data
 {
   const struct rustls_client_config *config;
@@ -101,9 +105,11 @@
   struct ssl_connect_data *const connssl = io_ctx->cf->ctx;
   CURLcode result;
   int ret = 0;
-  ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
-                                    (char *)buf, len, &result);
-  if(nread < 0) {
+  size_t nread;
+
+  result = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
+                             (char *)buf, len, &nread);
+  if(result) {
     nread = 0;
     /* !checksrc! disable ERRNOVAR 4 */
     if(CURLE_AGAIN == result)
@@ -114,8 +120,8 @@
   else if(nread == 0)
     connssl->peer_closed = TRUE;
   *out_n = (uintptr_t)nread;
-  CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
-              len, nread, result);
+  CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %d, %zu",
+              len, result, nread);
   return ret;
 }
 
@@ -125,10 +131,11 @@
   const struct io_ctx *io_ctx = userdata;
   CURLcode result;
   int ret = 0;
-  ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
-                                       (const char *)buf, len, FALSE,
-                                       &result);
-  if(nwritten < 0) {
+  size_t nwritten;
+
+  result = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
+                             (const char *)buf, len, FALSE, &nwritten);
+  if(result) {
     nwritten = 0;
     if(CURLE_AGAIN == result)
       ret = EAGAIN;
@@ -136,8 +143,8 @@
       ret = EINVAL;
   }
   *out_n = (uintptr_t)nwritten;
-  CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
-              len, nwritten, result);
+  CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %d, %zu",
+              len, result, nwritten);
   return ret;
 }
 
@@ -192,37 +199,37 @@
  * buffer, and process packets, but will not consume bytes from Rustls'
  * plaintext output buffer.
  */
-static ssize_t
+static CURLcode
 cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-            char *plainbuf, size_t plainlen, CURLcode *err)
+        char *plainbuf, size_t plainlen, size_t *pnread)
 {
   const struct ssl_connect_data *const connssl = cf->ctx;
   struct rustls_ssl_backend_data *const backend =
     (struct rustls_ssl_backend_data *)connssl->backend;
   struct rustls_connection *rconn = NULL;
+  CURLcode result = CURLE_OK;
   size_t n = 0;
-  size_t plain_bytes_copied = 0;
   rustls_result rresult = 0;
-  ssize_t nread;
   bool eof = FALSE;
 
   DEBUGASSERT(backend);
+  *pnread = 0;
   rconn = backend->conn;
 
-  while(plain_bytes_copied < plainlen) {
+  while(*pnread < plainlen) {
     if(!backend->data_in_pending) {
-      if(tls_recv_more(cf, data, err) < 0) {
-        if(*err != CURLE_AGAIN) {
-          nread = -1;
+      if(tls_recv_more(cf, data, &result) < 0) {
+        if(result != CURLE_AGAIN) {
           goto out;
         }
+        result = CURLE_OK;
         break;
       }
     }
 
     rresult = rustls_connection_read(rconn,
-                                     (uint8_t *)plainbuf + plain_bytes_copied,
-                                     plainlen - plain_bytes_copied,
+                                     (uint8_t *)plainbuf + *pnread,
+                                     plainlen - *pnread,
                                      &n);
     if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
       backend->data_in_pending = FALSE;
@@ -230,15 +237,13 @@
     else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
       failf(data, "rustls: peer closed TCP connection "
             "without first closing TLS connection");
-      *err = CURLE_RECV_ERROR;
-      nread = -1;
+      result = CURLE_RECV_ERROR;
       goto out;
     }
     else if(rresult != RUSTLS_RESULT_OK) {
       /* n always equals 0 in this case, do not need to check it */
       rustls_failf(data, rresult, "rustls_connection_read");
-      *err = CURLE_RECV_ERROR;
-      nread = -1;
+      result = CURLE_RECV_ERROR;
       goto out;
     }
     else if(n == 0) {
@@ -249,27 +254,18 @@
       break;
     }
     else {
-      plain_bytes_copied += n;
+      *pnread += n;
     }
   }
 
-  if(plain_bytes_copied) {
-    *err = CURLE_OK;
-    nread = (ssize_t)plain_bytes_copied;
-  }
-  else if(eof) {
-    *err = CURLE_OK;
-    nread = 0;
-  }
-  else {
-    *err = CURLE_AGAIN;
-    nread = -1;
+  if(!eof && !*pnread) {
+    result = CURLE_AGAIN;
   }
 
 out:
-  CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d",
-              plainlen, nread, *err);
-  return nread;
+  CURL_TRC_CF(data, cf, "rustls_recv(len=%zu) -> %d, %zu",
+              plainlen, result, *pnread);
+  return result;
 }
 
 static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -317,9 +313,9 @@
  * In that case, it will not read anything into Rustls' plaintext input buffer.
  * It will only drain Rustls' plaintext output buffer into the socket.
  */
-static ssize_t
+static CURLcode
 cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-        const void *plainbuf, size_t plainlen, CURLcode *err)
+        const void *plainbuf, size_t plainlen, size_t *pnwritten)
 {
   const struct ssl_connect_data *const connssl = cf->ctx;
   struct rustls_ssl_backend_data *const backend =
@@ -327,10 +323,11 @@
   struct rustls_connection *rconn = NULL;
   size_t plainwritten = 0;
   const unsigned char *buf = plainbuf;
+  CURLcode result = CURLE_OK;
   size_t blen = plainlen;
-  ssize_t nwritten = 0;
 
   DEBUGASSERT(backend);
+  *pnwritten = 0;
   rconn = backend->conn;
   DEBUGASSERT(rconn);
 
@@ -341,18 +338,18 @@
    * if successful, deduct the previous plain bytes from the current
    * send. */
   if(backend->plain_out_buffered) {
-    *err = cr_flush_out(cf, data, rconn);
+    result = cr_flush_out(cf, data, rconn);
     CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d",
-                backend->plain_out_buffered, *err);
-    if(*err)
-      return -1;
+                backend->plain_out_buffered, result);
+    if(result)
+      return result;
     if(blen > backend->plain_out_buffered) {
       blen -= backend->plain_out_buffered;
       buf += backend->plain_out_buffered;
     }
     else
       blen = 0;
-    nwritten += (ssize_t)backend->plain_out_buffered;
+    *pnwritten += (ssize_t)backend->plain_out_buffered;
     backend->plain_out_buffered = 0;
   }
 
@@ -362,37 +359,35 @@
     rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
     if(rresult != RUSTLS_RESULT_OK) {
       rustls_failf(data, rresult, "rustls_connection_write");
-      *err = CURLE_WRITE_ERROR;
-      return -1;
+      result = CURLE_WRITE_ERROR;
+      goto out;
     }
     else if(plainwritten == 0) {
       failf(data, "rustls_connection_write: EOF");
-      *err = CURLE_WRITE_ERROR;
-      return -1;
+      result = CURLE_WRITE_ERROR;
+      goto out;
     }
   }
 
-  *err = cr_flush_out(cf, data, rconn);
-  if(*err) {
-    if(CURLE_AGAIN == *err) {
+  result = cr_flush_out(cf, data, rconn);
+  if(result) {
+    if(CURLE_AGAIN == result) {
       /* The TLS bytes may have been partially written, but we fail the
        * complete send() and remember how much we already added to Rustls. */
-      CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain"
-                  " bytes already to Rustls", blen);
       backend->plain_out_buffered = plainwritten;
-      if(nwritten) {
-        *err = CURLE_OK;
-        return (ssize_t)nwritten;
+      if(*pnwritten) {
+        result = CURLE_OK;
       }
     }
-    return -1;
+    goto out;
   }
   else
-    nwritten += (ssize_t)plainwritten;
+    *pnwritten += (ssize_t)plainwritten;
 
-  CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zd",
-              plainlen, *err, nwritten);
-  return nwritten;
+out:
+  CURL_TRC_CF(data, cf, "rustls_send(len=%zu) -> %d, %zd",
+              plainlen, result, *pnwritten);
+  return result;
 }
 
 /* A server certificate verify callback for Rustls that always returns
@@ -864,7 +859,7 @@
   }
   else if(!conn_config->clientcert && ssl_config->key) {
     failf(data, "rustls: must provide certificate with key '%s'",
-          conn_config->clientcert);
+          ssl_config->key);
     return CURLE_SSL_CERTPROBLEM;
   }
 
@@ -1181,8 +1176,9 @@
        * send its FINISHED message off. We attempt to let it write
        * one more time. Oh my.
        */
+      size_t nwritten;
       cr_set_negotiated_alpn(cf, data, rconn);
-      cr_send(cf, data, NULL, 0, &tmperr);
+      tmperr = cr_send(cf, data, NULL, 0, &nwritten);
       if(tmperr == CURLE_AGAIN) {
         connssl->io_need = CURL_SSL_IO_NEED_SEND;
         return CURLE_OK;
@@ -1194,17 +1190,23 @@
       {
         const uint16_t proto =
           rustls_connection_get_protocol_version(rconn);
-        const uint16_t cipher =
-          rustls_connection_get_negotiated_ciphersuite(rconn);
-        char buf[64] = "";
+        const rustls_str ciphersuite_name =
+          rustls_connection_get_negotiated_ciphersuite_name(rconn);
+        const rustls_str kex_group_name =
+          rustls_connection_get_negotiated_key_exchange_group_name(rconn);
         const char *ver = "TLS version unknown";
         if(proto == RUSTLS_TLS_VERSION_TLSV1_3)
           ver = "TLSv1.3";
         if(proto == RUSTLS_TLS_VERSION_TLSV1_2)
           ver = "TLSv1.2";
-        Curl_cipher_suite_get_str(cipher, buf, sizeof(buf), TRUE);
-        infof(data, "rustls: handshake complete, %s, cipher: %s",
-              ver, buf);
+        infof(data,
+              "rustls: handshake complete, %s, ciphersuite: %.*s, "
+              "key exchange group: %.*s",
+              ver,
+              (int) ciphersuite_name.len,
+              ciphersuite_name.data,
+              (int) kex_group_name.len,
+              kex_group_name.data);
       }
       if(data->set.ssl.certinfo) {
         size_t num_certs = 0;
@@ -1255,8 +1257,9 @@
     DEBUGASSERT(wants_read || wants_write);
 
     if(wants_write) {
+      size_t nwritten;
       CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
-      cr_send(cf, data, NULL, 0, &tmperr);
+      tmperr = cr_send(cf, data, NULL, 0, &nwritten);
       if(tmperr == CURLE_AGAIN) {
         CURL_TRC_CF(data, cf, "writing would block");
         connssl->io_need = CURL_SSL_IO_NEED_SEND;
@@ -1309,8 +1312,7 @@
   struct rustls_ssl_backend_data *backend =
     (struct rustls_ssl_backend_data *)connssl->backend;
   CURLcode result = CURLE_OK;
-  ssize_t nwritten, nread;
-  size_t i;
+  size_t i, nread, nwritten;
 
   DEBUGASSERT(backend);
   if(!backend->conn || cf->shutdown) {
@@ -1329,8 +1331,8 @@
     }
   }
 
-  nwritten = cr_send(cf, data, NULL, 0, &result);
-  if(nwritten < 0) {
+  result = cr_send(cf, data, NULL, 0, &nwritten);
+  if(result) {
     if(result == CURLE_AGAIN) {
       connssl->io_need = CURL_SSL_IO_NEED_SEND;
       result = CURLE_OK;
@@ -1343,26 +1345,23 @@
 
   for(i = 0; i < 10; ++i) {
     char buf[1024];
-    nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result);
-    if(nread <= 0)
+    result = cr_recv(cf, data, buf, (int)sizeof(buf), &nread);
+    if(result)
       break;
   }
 
-  if(nread > 0) {
-    /* still data coming in? */
+  if(result == CURLE_AGAIN) {
+    connssl->io_need = CURL_SSL_IO_NEED_RECV;
+    result = CURLE_OK;
+  }
+  else if(result) {
+    DEBUGASSERT(result);
+    CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
   }
   else if(nread == 0) {
     /* We got the close notify alert and are done. */
     *done = TRUE;
   }
-  else if(result == CURLE_AGAIN) {
-    connssl->io_need = CURL_SSL_IO_NEED_RECV;
-    result = CURLE_OK;
-  }
-  else {
-    DEBUGASSERT(result);
-    CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
-  }
 
 out:
   cf->shutdown = (result || *done);
@@ -1434,7 +1433,6 @@
   NULL,                            /* set_engine */
   NULL,                            /* set_engine_default */
   NULL,                            /* engines_list */
-  NULL,                            /* false_start */
   NULL,                            /* sha256sum */
   cr_recv,                         /* recv decrypted data */
   cr_send,                         /* send data to encrypt */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index bea8eef..2ac61ba 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -42,9 +42,9 @@
 #include "vtls.h"
 #include "vtls_int.h"
 #include "vtls_scache.h"
-#include "../strcase.h"
 #include "../sendf.h"
 #include "../connect.h" /* for the connect timeout */
+#include "../strdup.h"
 #include "../strerror.h"
 #include "../select.h" /* for the socket readiness */
 #include "../curlx/inet_pton.h" /* for IP addr SNI check */
@@ -598,7 +598,7 @@
     }
 
     if((fInCert || blob) && (data->set.ssl.cert_type) &&
-       (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
+       (!curl_strequal(data->set.ssl.cert_type, "P12"))) {
       failf(data, "schannel: certificate format compatibility error "
             " for %s",
             blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
@@ -897,7 +897,7 @@
 static CURLcode
 schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
-  ssize_t written = -1;
+  size_t written = 0;
   struct ssl_connect_data *connssl = cf->ctx;
   struct schannel_ssl_backend_data *backend =
     (struct schannel_ssl_backend_data *)connssl->backend;
@@ -1128,18 +1128,18 @@
                "sending %lu bytes.", outbuf.cbBuffer));
 
   /* send initial handshake data which is now stored in output buffer */
-  written = Curl_conn_cf_send(cf->next, data,
-                              outbuf.pvBuffer, outbuf.cbBuffer, FALSE,
-                              &result);
+  result = Curl_conn_cf_send(cf->next, data,
+                             outbuf.pvBuffer, outbuf.cbBuffer, FALSE,
+                             &written);
   Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
-  if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
+  if((result != CURLE_OK) || (outbuf.cbBuffer != written)) {
     failf(data, "schannel: failed to send initial handshake data: "
-          "sent %zd of %lu bytes", written, outbuf.cbBuffer);
+          "sent %zu of %lu bytes", written, outbuf.cbBuffer);
     return CURLE_SSL_CONNECT_ERROR;
   }
 
   DEBUGF(infof(data, "schannel: sent initial handshake data: "
-               "sent %zd bytes", written));
+               "sent %zu bytes", written));
 
   backend->recv_unrecoverable_err = CURLE_OK;
   backend->recv_sspi_close_notify = FALSE;
@@ -1161,7 +1161,7 @@
     (struct schannel_ssl_backend_data *)connssl->backend;
   struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
   int i;
-  ssize_t nread = -1, written = -1;
+  size_t nread = 0, written = 0;
   unsigned char *reallocated_buffer;
   SecBuffer outbuf[3];
   SecBufferDesc outbuf_desc;
@@ -1229,12 +1229,12 @@
   for(;;) {
     if(doread) {
       /* read encrypted handshake data from socket */
-      nread = Curl_conn_cf_recv(cf->next, data,
-                               (char *) (backend->encdata_buffer +
-                                         backend->encdata_offset),
-                               backend->encdata_length -
-                               backend->encdata_offset,
-                               &result);
+      result = Curl_conn_cf_recv(cf->next, data,
+                                 (char *) (backend->encdata_buffer +
+                                           backend->encdata_offset),
+                                 backend->encdata_length -
+                                 backend->encdata_offset,
+                                 &nread);
       if(result == CURLE_AGAIN) {
         connssl->io_need = CURL_SSL_IO_NEED_RECV;
         DEBUGF(infof(data, "schannel: failed to receive handshake, "
@@ -1250,7 +1250,7 @@
       /* increase encrypted data buffer offset */
       backend->encdata_offset += nread;
       backend->encdata_is_incomplete = FALSE;
-      SCH_DEV(infof(data, "schannel: encrypted data got %zd", nread));
+      SCH_DEV(infof(data, "schannel: encrypted data got %zu", nread));
     }
 
     SCH_DEV(infof(data,
@@ -1317,13 +1317,13 @@
                        "sending %lu bytes.", outbuf[i].cbBuffer));
 
           /* send handshake token to server */
-          written = Curl_conn_cf_send(cf->next, data,
-                                      outbuf[i].pvBuffer, outbuf[i].cbBuffer,
-                                      FALSE, &result);
+          result = Curl_conn_cf_send(cf->next, data,
+                                     outbuf[i].pvBuffer, outbuf[i].cbBuffer,
+                                     FALSE, &written);
           if((result != CURLE_OK) ||
-             (outbuf[i].cbBuffer != (size_t) written)) {
+             (outbuf[i].cbBuffer != written)) {
             failf(data, "schannel: failed to send next handshake data: "
-                  "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
+                  "sent %zu of %lu bytes", written, outbuf[i].cbBuffer);
             return CURLE_SSL_CONNECT_ERROR;
           }
         }
@@ -1714,22 +1714,22 @@
   return CURLE_OK;
 }
 
-static ssize_t
+static CURLcode
 schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
-              const void *buf, size_t len, CURLcode *err)
+              const void *buf, size_t len, size_t *pnwritten)
 {
-  ssize_t written = -1;
   size_t data_len = 0;
   unsigned char *ptr = NULL;
   struct ssl_connect_data *connssl = cf->ctx;
   SecBuffer outbuf[4];
   SecBufferDesc outbuf_desc;
   SECURITY_STATUS sspi_status = SEC_E_OK;
-  CURLcode result;
+  CURLcode result = CURLE_OK;
   struct schannel_ssl_backend_data *backend =
     (struct schannel_ssl_backend_data *)connssl->backend;
 
   DEBUGASSERT(backend);
+  *pnwritten = 0;
 
   /* check if the maximum stream sizes were queried */
   if(backend->stream_sizes.cbMaximumMessage == 0) {
@@ -1738,8 +1738,7 @@
       SECPKG_ATTR_STREAM_SIZES,
       &backend->stream_sizes);
     if(sspi_status != SEC_E_OK) {
-      *err = CURLE_SEND_ERROR;
-      return -1;
+      return CURLE_SEND_ERROR;
     }
   }
 
@@ -1753,8 +1752,7 @@
     backend->stream_sizes.cbTrailer;
   ptr = (unsigned char *) malloc(data_len);
   if(!ptr) {
-    *err = CURLE_OUT_OF_MEMORY;
-    return -1;
+    return CURLE_OUT_OF_MEMORY;
   }
 
   /* setup output buffers (header, data, trailer, empty) */
@@ -1777,7 +1775,6 @@
 
   /* check if the message was encrypted */
   if(sspi_status == SEC_E_OK) {
-    written = 0;
 
     /* send the encrypted message including header, data and trailer */
     len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
@@ -1799,16 +1796,15 @@
     */
 
     /* send entire message or fail */
-    while(len > (size_t)written) {
-      ssize_t this_write = 0;
+    while(len > *pnwritten) {
+      size_t this_write = 0;
       int what;
       timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE);
       if(timeout_ms < 0) {
         /* we already got the timeout */
         failf(data, "schannel: timed out sending data "
-              "(bytes sent: %zd)", written);
-        *err = CURLE_OPERATION_TIMEDOUT;
-        written = -1;
+              "(bytes sent: %zu)", *pnwritten);
+        result = CURLE_OPERATION_TIMEDOUT;
         break;
       }
       else if(!timeout_ms)
@@ -1817,56 +1813,52 @@
       if(what < 0) {
         /* fatal error */
         failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
-        *err = CURLE_SEND_ERROR;
-        written = -1;
+        result = CURLE_SEND_ERROR;
         break;
       }
       else if(0 == what) {
         failf(data, "schannel: timed out sending data "
-              "(bytes sent: %zd)", written);
-        *err = CURLE_OPERATION_TIMEDOUT;
-        written = -1;
+              "(bytes sent: %zu)", *pnwritten);
+        result = CURLE_OPERATION_TIMEDOUT;
         break;
       }
       /* socket is writable */
 
-       this_write = Curl_conn_cf_send(cf->next, data,
-                                      ptr + written, len - written,
-                                      FALSE, &result);
+       result = Curl_conn_cf_send(cf->next, data,
+                                  ptr + *pnwritten, len - *pnwritten,
+                                  FALSE, &this_write);
       if(result == CURLE_AGAIN)
         continue;
       else if(result != CURLE_OK) {
-        *err = result;
-        written = -1;
         break;
       }
 
-      written += this_write;
+      *pnwritten += this_write;
     }
   }
   else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
-    *err = CURLE_OUT_OF_MEMORY;
+    result = CURLE_OUT_OF_MEMORY;
   }
   else{
-    *err = CURLE_SEND_ERROR;
+    result = CURLE_SEND_ERROR;
   }
 
   Curl_safefree(ptr);
 
-  if(len == (size_t)written)
+  if(len == *pnwritten)
     /* Encrypted message including header, data and trailer entirely sent.
        The return value is the number of unencrypted bytes that were sent. */
-    written = outbuf[1].cbBuffer;
+    *pnwritten = outbuf[1].cbBuffer;
 
-  return written;
+  return result;
 }
 
-static ssize_t
+static CURLcode
 schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
-              char *buf, size_t len, CURLcode *err)
+              char *buf, size_t len, size_t *pnread)
 {
   size_t size = 0;
-  ssize_t nread = -1;
+  size_t nread = 0;
   struct ssl_connect_data *connssl = cf->ctx;
   unsigned char *reallocated_buffer;
   size_t reallocated_length;
@@ -1879,8 +1871,10 @@
   size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
   struct schannel_ssl_backend_data *backend =
     (struct schannel_ssl_backend_data *)connssl->backend;
+  CURLcode result = CURLE_OK;
 
   DEBUGASSERT(backend);
+  *pnread = 0;
 
   /****************************************************************************
    * Do not return or set backend->recv_unrecoverable_err unless in the
@@ -1899,7 +1893,6 @@
    */
 
   SCH_DEV(infof(data, "schannel: client wants to read %zu bytes", len));
-  *err = CURLE_OK;
 
   if(len && len <= backend->decdata_offset) {
     SCH_DEV(infof(data,
@@ -1907,7 +1900,7 @@
     goto cleanup;
   }
   else if(backend->recv_unrecoverable_err) {
-    *err = backend->recv_unrecoverable_err;
+    result = backend->recv_unrecoverable_err;
     infof(data, "schannel: an unrecoverable error occurred in a prior call");
     goto cleanup;
   }
@@ -1933,7 +1926,7 @@
       reallocated_buffer = realloc(backend->encdata_buffer,
                                    reallocated_length);
       if(!reallocated_buffer) {
-        *err = CURLE_OUT_OF_MEMORY;
+        result = CURLE_OUT_OF_MEMORY;
         failf(data, "schannel: unable to re-allocate memory");
         goto cleanup;
       }
@@ -1950,26 +1943,26 @@
                   backend->encdata_offset, backend->encdata_length));
 
     /* read encrypted data from socket */
-    nread = Curl_conn_cf_recv(cf->next, data,
-                              (char *)(backend->encdata_buffer +
-                                    backend->encdata_offset),
-                              size, err);
-    if(*err) {
-      if(*err == CURLE_AGAIN)
+    result = Curl_conn_cf_recv(cf->next, data,
+                             (char *)(backend->encdata_buffer +
+                                      backend->encdata_offset),
+                             size, &nread);
+    if(result) {
+      if(result == CURLE_AGAIN)
         SCH_DEV(infof(data, "schannel: recv returned CURLE_AGAIN"));
-      else if(*err == CURLE_RECV_ERROR)
+      else if(result == CURLE_RECV_ERROR)
         infof(data, "schannel: recv returned CURLE_RECV_ERROR");
       else
-        infof(data, "schannel: recv returned error %d", *err);
+        infof(data, "schannel: recv returned error %d", result);
     }
     else if(nread == 0) {
       backend->recv_connection_closed = TRUE;
       DEBUGF(infof(data, "schannel: server closed the connection"));
     }
-    else if(nread > 0) {
-      backend->encdata_offset += (size_t)nread;
+    else {
+      backend->encdata_offset += nread;
       backend->encdata_is_incomplete = FALSE;
-      SCH_DEV(infof(data, "schannel: encrypted data got %zd", nread));
+      SCH_DEV(infof(data, "schannel: encrypted data got %zu", nread));
     }
   }
 
@@ -2019,7 +2012,7 @@
           reallocated_buffer = realloc(backend->decdata_buffer,
                                        reallocated_length);
           if(!reallocated_buffer) {
-            *err = CURLE_OUT_OF_MEMORY;
+            result = CURLE_OUT_OF_MEMORY;
             failf(data, "schannel: unable to re-allocate memory");
             goto cleanup;
           }
@@ -2070,7 +2063,7 @@
       /* check if server wants to renegotiate the connection context */
       if(sspi_status == SEC_I_RENEGOTIATE) {
         infof(data, "schannel: remote party requests renegotiation");
-        if(*err && *err != CURLE_AGAIN) {
+        if(result && result != CURLE_AGAIN) {
           infof(data, "schannel: cannot renegotiate, an error is pending");
           goto cleanup;
         }
@@ -2081,9 +2074,9 @@
         connssl->connecting_state = ssl_connect_2;
         connssl->io_need = CURL_SSL_IO_NEED_SEND;
         backend->recv_renegotiating = TRUE;
-        *err = schannel_connect(cf, data, &done);
+        result = schannel_connect(cf, data, &done);
         backend->recv_renegotiating = FALSE;
-        if(*err) {
+        if(result) {
           infof(data, "schannel: renegotiation failed");
           goto cleanup;
         }
@@ -2102,8 +2095,8 @@
         /* We received the close notify just fine, any error we got
          * from the lower filters afterwards (e.g. the socket), is not
          * an error on the TLS data stream. That one ended here. */
-        if(*err == CURLE_RECV_ERROR)
-          *err = CURLE_OK;
+        if(result == CURLE_RECV_ERROR)
+          result = CURLE_OK;
         infof(data,
               "schannel: server close notification received (close_notify)");
         goto cleanup;
@@ -2111,8 +2104,8 @@
     }
     else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
       backend->encdata_is_incomplete = TRUE;
-      if(!*err)
-        *err = CURLE_AGAIN;
+      if(!result)
+        result = CURLE_AGAIN;
       SCH_DEV(infof(data, "schannel: failed to decrypt data, need more data"));
       goto cleanup;
     }
@@ -2122,7 +2115,7 @@
       failf(data, "schannel: failed to read data from server: %s",
             Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
 #endif
-      *err = CURLE_RECV_ERROR;
+      result = CURLE_RECV_ERROR;
       goto cleanup;
     }
   }
@@ -2142,28 +2135,16 @@
      The behavior here is a matter of debate. We do not want to be vulnerable
      to a truncation attack however there is some browser precedent for
      ignoring the close_notify for compatibility reasons.
-
-     Additionally, Windows 2000 (v5.0) is a special case since it seems it
-     does not return close_notify. In that case if the connection was closed we
-     assume it was graceful (close_notify) since there does not seem to be a
-     way to tell.
   */
   if(len && !backend->decdata_offset && backend->recv_connection_closed &&
      !backend->recv_sspi_close_notify) {
-    bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
-                                                VERSION_EQUAL);
-
-    if(isWin2k && sspi_status == SEC_E_OK)
-      backend->recv_sspi_close_notify = TRUE;
-    else {
-      *err = CURLE_RECV_ERROR;
-      failf(data, "schannel: server closed abruptly (missing close_notify)");
-    }
+    result = CURLE_RECV_ERROR;
+    failf(data, "schannel: server closed abruptly (missing close_notify)");
   }
 
   /* Any error other than CURLE_AGAIN is an unrecoverable error. */
-  if(*err && *err != CURLE_AGAIN)
-    backend->recv_unrecoverable_err = *err;
+  if(result && result != CURLE_AGAIN)
+    backend->recv_unrecoverable_err = result;
 
   size = len < backend->decdata_offset ? len : backend->decdata_offset;
   if(size) {
@@ -2175,21 +2156,21 @@
     SCH_DEV(infof(data,
                   "schannel: decrypted data buffer: offset %zu length %zu",
                   backend->decdata_offset, backend->decdata_length));
-    *err = CURLE_OK;
-    return (ssize_t)size;
+    *pnread = size;
+    return CURLE_OK;
   }
 
-  if(!*err && !backend->recv_connection_closed)
-    *err = CURLE_AGAIN;
+  if(!result && !backend->recv_connection_closed)
+    result = CURLE_AGAIN;
 
   /* it is debatable what to return when !len. We could return whatever error
      we got from decryption but instead we override here so the return is
      consistent.
   */
   if(!len)
-    *err = CURLE_OK;
+    return CURLE_OK;
 
-  return *err ? -1 : 0;
+  return result;
 }
 
 static bool schannel_data_pending(struct Curl_cfilter *cf,
@@ -2291,14 +2272,16 @@
 
     if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
       /* send close message which is in output buffer */
-      ssize_t written = Curl_conn_cf_send(cf->next, data,
-                                          outbuf.pvBuffer, outbuf.cbBuffer,
-                                          FALSE, &result);
+      size_t written;
+
+      result = Curl_conn_cf_send(cf->next, data,
+                                 outbuf.pvBuffer, outbuf.cbBuffer,
+                                 FALSE, &written);
       Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
       if(!result) {
-        if(written < (ssize_t)outbuf.cbBuffer) {
+        if(written < outbuf.cbBuffer) {
           failf(data, "schannel: failed to send close msg: %s"
-                " (bytes written: %zd)", curl_easy_strerror(result), written);
+                " (bytes written: %zu)", curl_easy_strerror(result), written);
           result = CURLE_SEND_ERROR;
           goto out;
         }
@@ -2329,23 +2312,23 @@
   if(backend->cred && backend->ctxt &&
      !backend->recv_sspi_close_notify && !backend->recv_connection_closed) {
     char buffer[1024];
-    ssize_t nread;
+    size_t nread;
 
-    nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result);
-    if(nread > 0) {
-      /* still data coming in? */
+    result = schannel_recv(cf, data, buffer, sizeof(buffer), &nread);
+    if(result == CURLE_AGAIN) {
+      connssl->io_need = CURL_SSL_IO_NEED_RECV;
+    }
+    else if(result) {
+      CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
+      result = CURLE_RECV_ERROR;
     }
     else if(nread == 0) {
       /* We got the close notify alert and are done. */
       backend->recv_connection_closed = TRUE;
       *done = TRUE;
     }
-    else if(nread < 0 && result == CURLE_AGAIN) {
-      connssl->io_need = CURL_SSL_IO_NEED_RECV;
-    }
     else {
-      CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
-      result = CURLE_RECV_ERROR;
+      /* still data coming in? */
     }
   }
 
@@ -2770,7 +2753,6 @@
   NULL,                              /* set_engine */
   NULL,                              /* set_engine_default */
   NULL,                              /* engines_list */
-  NULL,                              /* false_start */
   schannel_sha256sum,                /* sha256sum */
   schannel_recv,                     /* recv decrypted data */
   schannel_send,                     /* send data to encrypt */
diff --git a/Utilities/cmcurl/lib/vtls/schannel_int.h b/Utilities/cmcurl/lib/vtls/schannel_int.h
index fe10125..511a852 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_int.h
+++ b/Utilities/cmcurl/lib/vtls/schannel_int.h
@@ -68,53 +68,51 @@
 #endif
 
 #ifndef SCH_CREDENTIALS_VERSION
-
 #define SCH_CREDENTIALS_VERSION  0x00000005
 
-typedef enum _eTlsAlgorithmUsage
-{
-    TlsParametersCngAlgUsageKeyExchange,
-    TlsParametersCngAlgUsageSignature,
-    TlsParametersCngAlgUsageCipher,
-    TlsParametersCngAlgUsageDigest,
-    TlsParametersCngAlgUsageCertSig
+typedef enum _eTlsAlgorithmUsage {
+  TlsParametersCngAlgUsageKeyExchange,
+  TlsParametersCngAlgUsageSignature,
+  TlsParametersCngAlgUsageCipher,
+  TlsParametersCngAlgUsageDigest,
+  TlsParametersCngAlgUsageCertSig
 } eTlsAlgorithmUsage;
 
-typedef struct _CRYPTO_SETTINGS
-{
-    eTlsAlgorithmUsage  eAlgorithmUsage;
-    UNICODE_STRING      strCngAlgId;
-    DWORD               cChainingModes;
-    PUNICODE_STRING     rgstrChainingModes;
-    DWORD               dwMinBitLength;
-    DWORD               dwMaxBitLength;
+/* !checksrc! disable TYPEDEFSTRUCT 1 */
+typedef struct _CRYPTO_SETTINGS {
+  eTlsAlgorithmUsage  eAlgorithmUsage;
+  UNICODE_STRING      strCngAlgId;
+  DWORD               cChainingModes;
+  PUNICODE_STRING     rgstrChainingModes;
+  DWORD               dwMinBitLength;
+  DWORD               dwMaxBitLength;
 } CRYPTO_SETTINGS, * PCRYPTO_SETTINGS;
 
-typedef struct _TLS_PARAMETERS
-{
-    DWORD               cAlpnIds;
-    PUNICODE_STRING     rgstrAlpnIds;
-    DWORD               grbitDisabledProtocols;
-    DWORD               cDisabledCrypto;
-    PCRYPTO_SETTINGS    pDisabledCrypto;
-    DWORD               dwFlags;
+/* !checksrc! disable TYPEDEFSTRUCT 1 */
+typedef struct _TLS_PARAMETERS {
+  DWORD               cAlpnIds;
+  PUNICODE_STRING     rgstrAlpnIds;
+  DWORD               grbitDisabledProtocols;
+  DWORD               cDisabledCrypto;
+  PCRYPTO_SETTINGS    pDisabledCrypto;
+  DWORD               dwFlags;
 } TLS_PARAMETERS, * PTLS_PARAMETERS;
 
-typedef struct _SCH_CREDENTIALS
-{
-    DWORD               dwVersion;
-    DWORD               dwCredFormat;
-    DWORD               cCreds;
-    PCCERT_CONTEXT* paCred;
-    HCERTSTORE          hRootStore;
+/* !checksrc! disable TYPEDEFSTRUCT 1 */
+typedef struct _SCH_CREDENTIALS {
+  DWORD               dwVersion;
+  DWORD               dwCredFormat;
+  DWORD               cCreds;
+  PCCERT_CONTEXT* paCred;
+  HCERTSTORE          hRootStore;
 
-    DWORD               cMappers;
-    struct _HMAPPER **aphMappers;
+  DWORD               cMappers;
+  struct _HMAPPER **aphMappers;
 
-    DWORD               dwSessionLifespan;
-    DWORD               dwFlags;
-    DWORD               cTlsParameters;
-    PTLS_PARAMETERS     pTlsParameters;
+  DWORD               dwSessionLifespan;
+  DWORD               dwFlags;
+  DWORD               cTlsParameters;
+  PTLS_PARAMETERS     pTlsParameters;
 } SCH_CREDENTIALS, * PSCH_CREDENTIALS;
 
 #define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index f843342..7db13f2 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -78,6 +78,28 @@
 #define BEGIN_CERT "-----BEGIN CERTIFICATE-----"
 #define END_CERT "\n-----END CERTIFICATE-----"
 
+struct cert_chain_engine_config_win8 {
+  DWORD cbSize;
+  HCERTSTORE hRestrictedRoot;
+  HCERTSTORE hRestrictedTrust;
+  HCERTSTORE hRestrictedOther;
+  DWORD cAdditionalStore;
+  HCERTSTORE *rghAdditionalStore;
+  DWORD dwFlags;
+  DWORD dwUrlRetrievalTimeout;
+  DWORD MaximumCachedCertificates;
+  DWORD CycleDetectionModulus;
+  HCERTSTORE hExclusiveRoot;
+  HCERTSTORE hExclusiveTrustedPeople;
+  DWORD dwExclusiveFlags;
+};
+
+/* Not defined before mingw-w64 4.0.0 */
+#ifndef CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG
+#define CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG 0x00000001
+#endif
+
+/* Legacy structure to supply size to Win7 clients */
 struct cert_chain_engine_config_win7 {
   DWORD cbSize;
   HCERTSTORE hRestrictedRoot;
@@ -838,13 +860,22 @@
     }
 
     if(result == CURLE_OK) {
-      struct cert_chain_engine_config_win7 engine_config;
+      struct cert_chain_engine_config_win8 engine_config;
       BOOL create_engine_result;
 
       memset(&engine_config, 0, sizeof(engine_config));
-      engine_config.cbSize = sizeof(engine_config);
       engine_config.hExclusiveRoot = trust_store;
 
+      /* Win8/Server2012 allows us to match partial chains */
+      if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
+                                      VERSION_GREATER_THAN_EQUAL) &&
+         !ssl_config->no_partialchain) {
+        engine_config.cbSize = sizeof(engine_config);
+        engine_config.dwExclusiveFlags = CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG;
+      }
+      else
+        engine_config.cbSize = sizeof(struct cert_chain_engine_config_win7);
+
       /* CertCreateCertificateChainEngine will check the expected size of the
        * CERT_CHAIN_ENGINE_CONFIG structure and fail if the specified size
        * does not match the expected size. When this occurs, it indicates that
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
deleted file mode 100644
index 2ae2ef3..0000000
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ /dev/null
@@ -1,2708 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- * Copyright (C) Nick Zitzmann, <nickzman@gmail.com>.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-/*
- * Source file for all iOS and macOS Secure Transport-specific code for the
- * TLS/SSL layer. No code but vtls.c should ever call or use these functions.
- */
-
-#include "../curl_setup.h"
-
-#ifdef USE_SECTRANSP
-
-#include "../urldata.h" /* for the Curl_easy definition */
-#include "../curlx/base64.h"
-#include "../curlx/strparse.h"
-#include "../multiif.h"
-#include "../strcase.h"
-#include "x509asn1.h"
-#include "vtls_scache.h"
-#include "../strerror.h"
-#include "cipher_suite.h"
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunreachable-code"
-#endif /* __clang__ */
-
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Waddress"
-#endif
-
-#if defined(__GNUC__) && defined(__APPLE__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
-#include <limits.h>
-
-#include <Security/Security.h>
-/* For some reason, when building for iOS, the omnibus header above does
- * not include SecureTransport.h as of iOS SDK 5.1. */
-#include <Security/SecureTransport.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <CommonCrypto/CommonDigest.h>
-
-/* The Security framework has changed greatly between iOS and different macOS
-   versions, and we will try to support as many of them as we can (back to
-   Leopard and iOS 5) by using macros and weak-linking.
-
-   In general, you want to build this using the most recent OS SDK, since some
-   features require curl to be built against the latest SDK. TLS 1.1 and 1.2
-   support, for instance, require the macOS 10.8 SDK or later. TLS 1.3
-   requires the macOS 10.13 or iOS 11 SDK or later. */
-#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
-
-#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
-#error "The Secure Transport backend requires Leopard or later."
-#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
-
-#define CURL_BUILD_IOS 0
-#define CURL_BUILD_IOS_7 0
-#define CURL_BUILD_IOS_9 0
-#define CURL_BUILD_IOS_11 0
-#define CURL_BUILD_IOS_13 0
-#define CURL_BUILD_MAC 1
-/* This is the maximum API level we are allowed to use when building: */
-#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
-#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
-#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
-#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
-#define CURL_BUILD_MAC_10_11 MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
-#define CURL_BUILD_MAC_10_13 MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
-#define CURL_BUILD_MAC_10_15 MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
-/* These macros mean "the following code is present to allow runtime backward
-   compatibility with at least this cat or earlier":
-   (You set this at build-time using the compiler command line option
-   "-mmacosx-version-min.") */
-#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
-#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
-#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
-#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
-#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
-
-#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
-#define CURL_BUILD_IOS 1
-#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
-#define CURL_BUILD_IOS_9 __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
-#define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
-#define CURL_BUILD_IOS_13 __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
-#define CURL_BUILD_MAC 0
-#define CURL_BUILD_MAC_10_5 0
-#define CURL_BUILD_MAC_10_6 0
-#define CURL_BUILD_MAC_10_7 0
-#define CURL_BUILD_MAC_10_8 0
-#define CURL_BUILD_MAC_10_9 0
-#define CURL_BUILD_MAC_10_11 0
-#define CURL_BUILD_MAC_10_13 0
-#define CURL_BUILD_MAC_10_15 0
-#define CURL_SUPPORT_MAC_10_5 0
-#define CURL_SUPPORT_MAC_10_6 0
-#define CURL_SUPPORT_MAC_10_7 0
-#define CURL_SUPPORT_MAC_10_8 0
-#define CURL_SUPPORT_MAC_10_9 0
-
-#else
-#error "The Secure Transport backend requires iOS or macOS."
-#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
-
-#if CURL_BUILD_MAC
-#include <sys/sysctl.h>
-#endif /* CURL_BUILD_MAC */
-
-#include "../sendf.h"
-#include "../curlx/inet_pton.h"
-#include "../connect.h"
-#include "../select.h"
-#include "vtls.h"
-#include "vtls_int.h"
-#include "sectransp.h"
-#include "../curl_printf.h"
-#include "../strdup.h"
-
-#include "../curl_memory.h"
-/* The last #include file should be: */
-#include "../memdebug.h"
-
-
-/* From MacTypes.h (which we cannot include because it is not present in
-   iOS: */
-#define ioErr -36
-#define paramErr -50
-
-struct st_ssl_backend_data {
-  SSLContextRef ssl_ctx;
-  bool ssl_direction; /* true if writing, false if reading */
-  size_t ssl_write_buffered_length;
-  BIT(sent_shutdown);
-};
-
-/* Create the list of default ciphers to use by making an intersection of the
- * ciphers supported by Secure Transport and the list below, using the order
- * of the former.
- * This list is based on TLS recommendations by Mozilla, balancing between
- * security and wide compatibility: "Most ciphers that are not clearly broken
- * and dangerous to use are supported"
- */
-static const uint16_t default_ciphers[] = {
-  TLS_RSA_WITH_3DES_EDE_CBC_SHA,                    /* 0x000A */
-  TLS_RSA_WITH_AES_128_CBC_SHA,                     /* 0x002F */
-  TLS_RSA_WITH_AES_256_CBC_SHA,                     /* 0x0035 */
-
-#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
-  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,             /* 0xC009 */
-  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,             /* 0xC00A */
-  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,               /* 0xC013 */
-  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,               /* 0xC014 */
-#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
-
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-  TLS_RSA_WITH_AES_128_CBC_SHA256,                  /* 0x003C */
-  TLS_RSA_WITH_AES_256_CBC_SHA256,                  /* 0x003D */
-  TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,              /* 0x0067 */
-  TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,              /* 0x006B */
-  TLS_RSA_WITH_AES_128_GCM_SHA256,                  /* 0x009C */
-  TLS_RSA_WITH_AES_256_GCM_SHA384,                  /* 0x009D */
-  TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,              /* 0x009E */
-  TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,              /* 0x009F */
-  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,          /* 0xC023 */
-  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,          /* 0xC024 */
-  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,            /* 0xC027 */
-  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,            /* 0xC028 */
-  TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,          /* 0xC02B */
-  TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,          /* 0xC02C */
-  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,            /* 0xC02F */
-  TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,            /* 0xC030 */
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-
-#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
-  TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,      /* 0xCCA8 */
-  TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,    /* 0xCCA9 */
-
-  /* TLSv1.3 is not supported by Secure Transport, but there is also other
-   * code referencing TLSv1.3, like: kTLSProtocol13 ? */
-  TLS_AES_128_GCM_SHA256,                           /* 0x1301 */
-  TLS_AES_256_GCM_SHA384,                           /* 0x1302 */
-  TLS_CHACHA20_POLY1305_SHA256,                     /* 0x1303 */
-#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
-};
-
-/* pinned public key support tests */
-
-/* version 1 supports macOS 10.12+ and iOS 10+ */
-#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
-    (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED  >= 101200))
-#define SECTRANSP_PINNEDPUBKEY_V1 1
-#endif
-
-/* version 2 supports macOS 10.7+ */
-#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
-#define SECTRANSP_PINNEDPUBKEY_V2 1
-#endif
-
-#if defined(SECTRANSP_PINNEDPUBKEY_V1) || defined(SECTRANSP_PINNEDPUBKEY_V2)
-/* this backend supports CURLOPT_PINNEDPUBLICKEY */
-#define SECTRANSP_PINNEDPUBKEY 1
-#endif /* SECTRANSP_PINNEDPUBKEY */
-
-#ifdef SECTRANSP_PINNEDPUBKEY
-/* both new and old APIs return rsa keys missing the spki header (not DER) */
-static const unsigned char rsa4096SpkiHeader[] = {
-                                       0x30, 0x82, 0x02, 0x22, 0x30, 0x0d,
-                                       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-                                       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
-                                       0x00, 0x03, 0x82, 0x02, 0x0f, 0x00};
-
-static const unsigned char rsa2048SpkiHeader[] = {
-                                       0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
-                                       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-                                       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
-                                       0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
-#ifdef SECTRANSP_PINNEDPUBKEY_V1
-/* the *new* version does not return DER encoded ecdsa certs like the old... */
-static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
-                                       0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
-                                       0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
-                                       0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
-                                       0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
-                                       0x42, 0x00};
-
-static const unsigned char ecDsaSecp384r1SpkiHeader[] = {
-                                       0x30, 0x76, 0x30, 0x10, 0x06, 0x07,
-                                       0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
-                                       0x01, 0x06, 0x05, 0x2b, 0x81, 0x04,
-                                       0x00, 0x22, 0x03, 0x62, 0x00};
-#endif /* SECTRANSP_PINNEDPUBKEY_V1 */
-#endif /* SECTRANSP_PINNEDPUBKEY */
-
-static OSStatus sectransp_bio_cf_in_read(SSLConnectionRef connection,
-                                         void *buf,
-                                         size_t *dataLength)  /* IN/OUT */
-{
-  const struct Curl_cfilter *cf = (const struct Curl_cfilter *)connection;
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nread;
-  CURLcode result;
-  OSStatus rtn = noErr;
-
-  DEBUGASSERT(data);
-  nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result);
-  CURL_TRC_CF(data, cf, "bio_read(len=%zu) -> %zd, result=%d",
-              *dataLength, nread, result);
-  if(nread < 0) {
-    switch(result) {
-      case CURLE_OK:
-      case CURLE_AGAIN:
-        rtn = errSSLWouldBlock;
-        backend->ssl_direction = FALSE;
-        break;
-      default:
-        rtn = ioErr;
-        break;
-    }
-    nread = 0;
-  }
-  else if(nread == 0) {
-    rtn = errSSLClosedGraceful;
-  }
-  else if((size_t)nread < *dataLength) {
-    rtn = errSSLWouldBlock;
-  }
-  *dataLength = nread;
-  return rtn;
-}
-
-static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection,
-                                           const void *buf,
-                                           size_t *dataLength)  /* IN/OUT */
-{
-  const struct Curl_cfilter *cf = (const struct Curl_cfilter *)connection;
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten;
-  CURLcode result;
-  OSStatus rtn = noErr;
-
-  DEBUGASSERT(data);
-  nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, FALSE,
-                               &result);
-  CURL_TRC_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d",
-              *dataLength, nwritten, result);
-  if(nwritten <= 0) {
-    if(result == CURLE_AGAIN) {
-      rtn = errSSLWouldBlock;
-      backend->ssl_direction = TRUE;
-    }
-    else {
-      rtn = ioErr;
-    }
-    nwritten = 0;
-  }
-  else if((size_t)nwritten < *dataLength) {
-    rtn = errSSLWouldBlock;
-  }
-  *dataLength = nwritten;
-  return rtn;
-}
-
-#if CURL_BUILD_MAC
-CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
-{
-  int mib[2];
-  size_t os_version_len;
-  char buf[256];
-
-  /* Get the Darwin kernel version from the kernel using sysctl(): */
-  mib[0] = CTL_KERN;
-  mib[1] = KERN_OSRELEASE;
-  if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1)
-    return;
-  if(os_version_len < sizeof(buf)) {
-    if(sysctl(mib, 2, buf, &os_version_len, NULL, 0) != -1) {
-      const char *os = buf;
-      curl_off_t fnum;
-      curl_off_t snum;
-      /* Parse the version: */
-      if(!curlx_str_number(&os, &fnum, INT_MAX) &&
-         !curlx_str_single(&os, '.') &&
-         !curlx_str_number(&os, &snum, INT_MAX)) {
-        *major = (int)fnum;
-        *minor = (int)snum;
-      }
-    }
-  }
-}
-#endif /* CURL_BUILD_MAC */
-
-/* Apple provides a myriad of ways of getting information about a certificate
-   into a string. Some are not available under iOS or newer cats. Here's a
-   unified function for getting a string describing the certificate that ought
-   to work in all cats starting with Leopard. */
-CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
-{
-  CFStringRef server_cert_summary = CFSTR("(null)");
-
-#if CURL_BUILD_IOS
-  /* iOS: There is only one way to do this. */
-  server_cert_summary = SecCertificateCopySubjectSummary(cert);
-#else
-#if CURL_BUILD_MAC_10_7
-  /* Lion & later: Get the long description if we can. */
-  if(&SecCertificateCopyLongDescription)
-    server_cert_summary =
-      SecCertificateCopyLongDescription(NULL, cert, NULL);
-  else
-#endif /* CURL_BUILD_MAC_10_7 */
-#if CURL_BUILD_MAC_10_6
-  /* Snow Leopard: Get the certificate summary. */
-  if(&SecCertificateCopySubjectSummary)
-    server_cert_summary = SecCertificateCopySubjectSummary(cert);
-  else
-#endif /* CURL_BUILD_MAC_10_6 */
-  /* Leopard is as far back as we go... */
-  (void)SecCertificateCopyCommonName(cert, &server_cert_summary);
-#endif /* CURL_BUILD_IOS */
-  return server_cert_summary;
-}
-
-static CURLcode CopyCertSubject(struct Curl_easy *data,
-                                SecCertificateRef cert, char **certp)
-{
-  CFStringRef c = getsubject(cert);
-  CURLcode result = CURLE_OK;
-  const char *direct;
-  char *cbuf = NULL;
-  *certp = NULL;
-
-  if(!c) {
-    failf(data, "SSL: invalid CA certificate subject");
-    return CURLE_PEER_FAILED_VERIFICATION;
-  }
-
-  /* If the subject is already available as UTF-8 encoded (ie 'direct') then
-     use that, else convert it. */
-  direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8);
-  if(direct) {
-    *certp = strdup(direct);
-    if(!*certp) {
-      failf(data, "SSL: out of memory");
-      result = CURLE_OUT_OF_MEMORY;
-    }
-  }
-  else {
-    size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
-    cbuf = calloc(1, cbuf_size);
-    if(cbuf) {
-      if(!CFStringGetCString(c, cbuf, (CFIndex)cbuf_size,
-                             kCFStringEncodingUTF8)) {
-        failf(data, "SSL: invalid CA certificate subject");
-        result = CURLE_PEER_FAILED_VERIFICATION;
-      }
-      else
-        /* pass back the buffer */
-        *certp = cbuf;
-    }
-    else {
-      failf(data, "SSL: could not allocate %zu bytes of memory", cbuf_size);
-      result = CURLE_OUT_OF_MEMORY;
-    }
-  }
-  if(result)
-    free(cbuf);
-  CFRelease(c);
-  return result;
-}
-
-#if CURL_SUPPORT_MAC_10_6
-/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
-   deprecation warnings, so let's not compile this unless it is necessary: */
-static OSStatus CopyIdentityWithLabelOldSchool(char *label,
-                                               SecIdentityRef *out_c_a_k)
-{
-  OSStatus status = errSecItemNotFound;
-  SecKeychainAttributeList attr_list;
-  SecKeychainAttribute attr;
-  SecKeychainSearchRef search = NULL;
-  SecCertificateRef cert = NULL;
-
-  /* Set up the attribute list: */
-  attr_list.count = 1L;
-  attr_list.attr = &attr;
-
-  /* Set up our lone search criterion: */
-  attr.tag = kSecLabelItemAttr;
-  attr.data = label;
-  attr.length = (UInt32)strlen(label);
-
-  /* Start searching: */
-  status = SecKeychainSearchCreateFromAttributes(NULL,
-                                                 kSecCertificateItemClass,
-                                                 &attr_list,
-                                                 &search);
-  if(status == noErr) {
-    status = SecKeychainSearchCopyNext(search,
-                                       (SecKeychainItemRef *)&cert);
-    if(status == noErr && cert) {
-      /* If we found a certificate, does it have a private key? */
-      status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k);
-      CFRelease(cert);
-    }
-  }
-
-  if(search)
-    CFRelease(search);
-  return status;
-}
-#endif /* CURL_SUPPORT_MAC_10_6 */
-
-static OSStatus CopyIdentityWithLabel(char *label,
-                                      SecIdentityRef *out_cert_and_key)
-{
-  OSStatus status = errSecItemNotFound;
-
-#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
-  CFArrayRef keys_list;
-  CFIndex keys_list_count;
-  CFIndex i;
-
-  /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
-     kSecClassIdentity was introduced in Lion. If both exist, let's use them
-     to find the certificate. */
-  if(&SecItemCopyMatching && kSecClassIdentity) {
-    CFTypeRef keys[5];
-    CFTypeRef values[5];
-    CFDictionaryRef query_dict;
-    CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
-      kCFStringEncodingUTF8);
-
-    /* Set up our search criteria and expected results: */
-    values[0] = kSecClassIdentity; /* we want a certificate and a key */
-    keys[0] = kSecClass;
-    values[1] = kCFBooleanTrue;    /* we want a reference */
-    keys[1] = kSecReturnRef;
-    values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the
-                                    * label matching below worked correctly */
-    keys[2] = kSecMatchLimit;
-    /* identity searches need a SecPolicyRef in order to work */
-    values[3] = SecPolicyCreateSSL(FALSE, NULL);
-    keys[3] = kSecMatchPolicy;
-    /* match the name of the certificate (does not work in macOS 10.12.1) */
-    values[4] = label_cf;
-    keys[4] = kSecAttrLabel;
-    query_dict = CFDictionaryCreate(NULL, (const void **)keys,
-                                    (const void **)values, 5L,
-                                    &kCFCopyStringDictionaryKeyCallBacks,
-                                    &kCFTypeDictionaryValueCallBacks);
-    CFRelease(values[3]);
-
-    /* Do we have a match? */
-    status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);
-
-    /* Because kSecAttrLabel matching does not work with kSecClassIdentity,
-     * we need to find the correct identity ourselves */
-    if(status == noErr) {
-      keys_list_count = CFArrayGetCount(keys_list);
-      *out_cert_and_key = NULL;
-      status = 1;
-      for(i = 0; i < keys_list_count; i++) {
-        OSStatus err = noErr;
-        SecCertificateRef cert = NULL;
-        const void *item = CFArrayGetValueAtIndex(keys_list, i);
-        SecIdentityRef identity = (SecIdentityRef)CURL_UNCONST(item);
-        err = SecIdentityCopyCertificate(identity, &cert);
-        if(err == noErr) {
-          CFStringRef common_name = NULL;
-          OSStatus copy_status = noErr;
-#if CURL_BUILD_IOS
-          common_name = SecCertificateCopySubjectSummary(cert);
-#elif CURL_BUILD_MAC_10_7
-          copy_status = SecCertificateCopyCommonName(cert, &common_name);
-#endif
-          if(copy_status == noErr &&
-            CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
-            CFRelease(cert);
-            CFRelease(common_name);
-            CFRetain(identity);
-            *out_cert_and_key = identity;
-            status = noErr;
-            break;
-          }
-          if(common_name)
-            CFRelease(common_name);
-        }
-        CFRelease(cert);
-      }
-    }
-
-    if(keys_list)
-      CFRelease(keys_list);
-    CFRelease(query_dict);
-    CFRelease(label_cf);
-  }
-  else {
-#if CURL_SUPPORT_MAC_10_6
-    /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */
-    status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
-#endif /* CURL_SUPPORT_MAC_10_6 */
-  }
-#elif CURL_SUPPORT_MAC_10_6
-  /* For developers building on older cats, we have no choice but to fall back
-     to SecKeychainSearch. */
-  status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
-#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
-  return status;
-}
-
-static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
-                                           const struct curl_blob *blob,
-                                           const char *cPassword,
-                                           SecIdentityRef *out_cert_and_key)
-{
-  OSStatus status = errSecItemNotFound;
-  CFURLRef pkcs_url = NULL;
-  CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
-    cPassword, kCFStringEncodingUTF8) : NULL;
-  CFDataRef pkcs_data = NULL;
-
-  /* We can import P12 files on iOS or macOS 10.7 or later: */
-  /* These constants are documented as having first appeared in 10.6 but they
-     raise linker errors when used on that cat for some reason. */
-#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
-  bool resource_imported;
-
-  if(blob) {
-    pkcs_data = CFDataCreate(kCFAllocatorDefault,
-                             (const unsigned char *)blob->data,
-                             (CFIndex)blob->len);
-    status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
-    resource_imported = (pkcs_data != NULL);
-  }
-  else {
-    pkcs_url =
-      CFURLCreateFromFileSystemRepresentation(NULL,
-                                              (const UInt8 *)cPath,
-                                              (CFIndex)strlen(cPath), FALSE);
-    resource_imported =
-      CFURLCreateDataAndPropertiesFromResource(NULL,
-                                               pkcs_url, &pkcs_data,
-                                               NULL, NULL, &status);
-  }
-
-  if(resource_imported) {
-    CFArrayRef items = NULL;
-
-  /* On iOS SecPKCS12Import will never add the client certificate to the
-   * Keychain.
-   *
-   * It gives us back a SecIdentityRef that we can use directly. */
-#if CURL_BUILD_IOS
-    const void *cKeys[] = {kSecImportExportPassphrase};
-    const void *cValues[] = {password};
-    CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
-      password ? 1L : 0L, NULL, NULL);
-
-    if(options) {
-      status = SecPKCS12Import(pkcs_data, options, &items);
-      CFRelease(options);
-    }
-
-
-  /* On macOS SecPKCS12Import will always add the client certificate to
-   * the Keychain.
-   *
-   * As this does not match iOS, and apps may not want to see their client
-   * certificate saved in the user's keychain, we use SecItemImport
-   * with a NULL keychain to avoid importing it.
-   *
-   * This returns a SecCertificateRef from which we can construct a
-   * SecIdentityRef.
-   */
-#elif CURL_BUILD_MAC_10_7
-    SecItemImportExportKeyParameters keyParams;
-    SecExternalFormat inputFormat = kSecFormatPKCS12;
-    SecExternalItemType inputType = kSecItemTypeCertificate;
-
-    memset(&keyParams, 0x00, sizeof(keyParams));
-    keyParams.version    = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
-    keyParams.passphrase = password;
-
-    status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType,
-                           0, &keyParams, NULL, &items);
-#endif
-
-
-    /* Extract the SecIdentityRef */
-    if(status == errSecSuccess && items && CFArrayGetCount(items)) {
-      CFIndex i, count;
-      count = CFArrayGetCount(items);
-
-      for(i = 0; i < count; i++) {
-        const CFTypeRef item = CFArrayGetValueAtIndex(items, i);
-        CFTypeID itemID = CFGetTypeID(item);
-
-        if(itemID == CFDictionaryGetTypeID()) {
-          const CFTypeRef identity = CFDictionaryGetValue(
-                                           (CFDictionaryRef)item,
-                                           kSecImportItemIdentity);
-          CFRetain(identity);
-          *out_cert_and_key = (SecIdentityRef)CURL_UNCONST(identity);
-          break;
-        }
-#if CURL_BUILD_MAC_10_7
-        else if(itemID == SecCertificateGetTypeID()) {
-          status = SecIdentityCreateWithCertificate(NULL,
-                                         (SecCertificateRef)CURL_UNCONST(item),
-                                         out_cert_and_key);
-          break;
-        }
-#endif
-      }
-    }
-
-    if(items)
-      CFRelease(items);
-    CFRelease(pkcs_data);
-  }
-#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
-  if(password)
-    CFRelease(password);
-  if(pkcs_url)
-    CFRelease(pkcs_url);
-  return status;
-}
-
-/* This code was borrowed from nss.c, with some modifications:
- * Determine whether the nickname passed in is a filename that needs to
- * be loaded as a PEM or a nickname.
- *
- * returns 1 for a file
- * returns 0 for not a file
- */
-CF_INLINE bool is_file(const char *filename)
-{
-  struct_stat st;
-
-  if(!filename)
-    return FALSE;
-
-  if(stat(filename, &st) == 0)
-    return S_ISREG(st.st_mode);
-  return FALSE;
-}
-
-static CURLcode
-sectransp_set_ssl_version_min_max(struct Curl_easy *data,
-                                  struct st_ssl_backend_data *backend,
-                                  struct ssl_primary_config *conn_config)
-{
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-  OSStatus err;
-  SSLProtocol ver_min;
-  SSLProtocol ver_max;
-
-#if CURL_SUPPORT_MAC_10_7
-  if(!&SSLSetProtocolVersionMax)
-    goto legacy;
-#endif
-
-  switch(conn_config->version) {
-    case CURL_SSLVERSION_DEFAULT:
-    case CURL_SSLVERSION_TLSv1:
-    case CURL_SSLVERSION_TLSv1_0:
-      ver_min = kTLSProtocol1;
-      break;
-    case CURL_SSLVERSION_TLSv1_1:
-      ver_min = kTLSProtocol11;
-      break;
-    case CURL_SSLVERSION_TLSv1_2:
-      ver_min = kTLSProtocol12;
-      break;
-    case CURL_SSLVERSION_TLSv1_3:
-    default:
-      failf(data, "SSL: unsupported minimum TLS version value");
-      return CURLE_SSL_CONNECT_ERROR;
-  }
-
-  switch(conn_config->version_max) {
-    case CURL_SSLVERSION_MAX_DEFAULT:
-    case CURL_SSLVERSION_MAX_NONE:
-    case CURL_SSLVERSION_MAX_TLSv1_3:
-    case CURL_SSLVERSION_MAX_TLSv1_2:
-      ver_max = kTLSProtocol12;
-      break;
-    case CURL_SSLVERSION_MAX_TLSv1_1:
-      ver_max = kTLSProtocol11;
-      break;
-    case CURL_SSLVERSION_MAX_TLSv1_0:
-      ver_max = kTLSProtocol1;
-      break;
-    default:
-      failf(data, "SSL: unsupported maximum TLS version value");
-      return CURLE_SSL_CONNECT_ERROR;
-  }
-
-  err = SSLSetProtocolVersionMin(backend->ssl_ctx, ver_min);
-  if(err != noErr) {
-    failf(data, "SSL: failed to set minimum TLS version");
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-  err = SSLSetProtocolVersionMax(backend->ssl_ctx, ver_max);
-  if(err != noErr) {
-    failf(data, "SSL: failed to set maximum TLS version");
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-
-  return CURLE_OK;
-#endif
-#if CURL_SUPPORT_MAC_10_7
-  goto legacy;
-legacy:
-  switch(conn_config->version) {
-    case CURL_SSLVERSION_DEFAULT:
-    case CURL_SSLVERSION_TLSv1:
-    case CURL_SSLVERSION_TLSv1_0:
-      break;
-    default:
-      failf(data, "SSL: unsupported minimum TLS version value");
-      return CURLE_SSL_CONNECT_ERROR;
-  }
-
-  /* only TLS 1.0 is supported, disable SSL 3.0 and SSL 2.0 */
-  SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, FALSE);
-  SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, TRUE);
-
-  return CURLE_OK;
-#endif
-}
-
-static int sectransp_cipher_suite_get_str(uint16_t id, char *buf,
-                                          size_t buf_size, bool prefer_rfc)
-{
-  /* are these fortezza suites even supported ? */
-  if(id == SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA)
-    msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA");
-  else if(id == SSL_FORTEZZA_DMS_WITH_NULL_SHA)
-    msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_NULL_SHA");
-  /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
-  else if(id == TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
-    msnprintf(buf, buf_size, "%s", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
-  /* do we still need to support these SSL2-only ciphers ? */
-  else if(id == SSL_RSA_WITH_RC2_CBC_MD5)
-    msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_RC2_CBC_MD5");
-  else if(id == SSL_RSA_WITH_IDEA_CBC_MD5)
-    msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_IDEA_CBC_MD5");
-  else if(id == SSL_RSA_WITH_DES_CBC_MD5)
-    msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_DES_CBC_MD5");
-  else if(id == SSL_RSA_WITH_3DES_EDE_CBC_MD5)
-    msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_3DES_EDE_CBC_MD5");
-  else
-    return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
-  return 0;
-}
-
-static uint16_t sectransp_cipher_suite_walk_str(const char **str,
-                                                const char **end)
-{
-  uint16_t id = Curl_cipher_suite_walk_str(str, end);
-  size_t len = *end - *str;
-
-  if(!id) {
-    /* are these fortezza suites even supported ? */
-    if(strncasecompare("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA", *str, len))
-      id = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA;
-    else if(strncasecompare("SSL_FORTEZZA_DMS_WITH_NULL_SHA", *str, len))
-      id = SSL_FORTEZZA_DMS_WITH_NULL_SHA;
-    /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
-    else if(strncasecompare("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", *str, len))
-      id = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
-    /* do we still need to support these SSL2-only ciphers ? */
-    else if(strncasecompare("SSL_RSA_WITH_RC2_CBC_MD5", *str, len))
-      id = SSL_RSA_WITH_RC2_CBC_MD5;
-    else if(strncasecompare("SSL_RSA_WITH_IDEA_CBC_MD5", *str, len))
-      id = SSL_RSA_WITH_IDEA_CBC_MD5;
-    else if(strncasecompare("SSL_RSA_WITH_DES_CBC_MD5", *str, len))
-      id = SSL_RSA_WITH_DES_CBC_MD5;
-    else if(strncasecompare("SSL_RSA_WITH_3DES_EDE_CBC_MD5", *str, len))
-      id = SSL_RSA_WITH_3DES_EDE_CBC_MD5;
-  }
-  return id;
-}
-
-/* allocated memory must be freed */
-static SSLCipherSuite * sectransp_get_supported_ciphers(SSLContextRef ssl_ctx,
-                                                        size_t *len)
-{
-  SSLCipherSuite *ciphers = NULL;
-  OSStatus err = noErr;
-  *len = 0;
-
-  err = SSLGetNumberSupportedCiphers(ssl_ctx, len);
-  if(err != noErr)
-    goto failed;
-
-  ciphers = malloc(*len * sizeof(SSLCipherSuite));
-  if(!ciphers)
-    goto failed;
-
-  err = SSLGetSupportedCiphers(ssl_ctx, ciphers, len);
-  if(err != noErr)
-    goto failed;
-
-#if CURL_BUILD_MAC
-  {
-    int maj = 0, min = 0;
-    GetDarwinVersionNumber(&maj, &min);
-    /* There is a known bug in early versions of Mountain Lion where ST's ECC
-       ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
-       Work around the problem here by disabling those ciphers if we are
-       running in an affected version of macOS. */
-    if(maj == 12 && min <= 3) {
-      size_t i = 0, j = 0;
-      for(; i < *len; i++) {
-        if(ciphers[i] >= 0xC001 && ciphers[i] <= 0xC032)
-          continue;
-        ciphers[j++] = ciphers[i];
-      }
-      *len = j;
-    }
-  }
-#endif
-
-  return ciphers;
-failed:
-  *len = 0;
-  Curl_safefree(ciphers);
-  return NULL;
-}
-
-static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
-                                              SSLContextRef ssl_ctx)
-{
-  CURLcode ret = CURLE_SSL_CIPHER;
-  size_t count = 0, i, j;
-  OSStatus err;
-  size_t supported_len;
-  SSLCipherSuite *ciphers = NULL;
-
-  ciphers = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
-  if(!ciphers) {
-    failf(data, "SSL: Failed to get supported ciphers");
-    goto failed;
-  }
-
-  /* Intersect the ciphers supported by Secure Transport with the default
-   * ciphers, using the order of the former. */
-  for(i = 0; i < supported_len; i++) {
-    for(j = 0; j < CURL_ARRAYSIZE(default_ciphers); j++) {
-      if(default_ciphers[j] == ciphers[i]) {
-        ciphers[count++] = ciphers[i];
-        break;
-      }
-    }
-  }
-
-  if(count == 0) {
-    failf(data, "SSL: no supported default ciphers");
-    goto failed;
-  }
-
-  err = SSLSetEnabledCiphers(ssl_ctx, ciphers, count);
-  if(err != noErr) {
-    failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
-    goto failed;
-  }
-
-  ret = CURLE_OK;
-failed:
-  Curl_safefree(ciphers);
-  return ret;
-}
-
-static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
-                                               SSLContextRef ssl_ctx,
-                                               const char *ciphers)
-{
-  CURLcode ret = CURLE_SSL_CIPHER;
-  size_t count = 0, i;
-  const char *ptr, *end;
-  OSStatus err;
-  size_t supported_len;
-  SSLCipherSuite *supported = NULL;
-  SSLCipherSuite *selected = NULL;
-
-  supported = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
-  if(!supported) {
-    failf(data, "SSL: Failed to get supported ciphers");
-    goto failed;
-  }
-
-  selected = malloc(supported_len * sizeof(SSLCipherSuite));
-  if(!selected) {
-    failf(data, "SSL: Failed to allocate memory");
-    goto failed;
-  }
-
-  for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
-    uint16_t id = sectransp_cipher_suite_walk_str(&ptr, &end);
-
-    /* Check if cipher is supported */
-    if(id) {
-      for(i = 0; i < supported_len && supported[i] != id; i++);
-      if(i == supported_len)
-        id = 0;
-    }
-    if(!id) {
-      if(ptr[0] != '\0')
-        infof(data, "SSL: unknown cipher in list: \"%.*s\"", (int) (end - ptr),
-              ptr);
-      continue;
-    }
-
-    /* No duplicates allowed (so selected cannot overflow) */
-    for(i = 0; i < count && selected[i] != id; i++);
-    if(i < count) {
-      infof(data, "SSL: duplicate cipher in list: \"%.*s\"", (int) (end - ptr),
-            ptr);
-      continue;
-    }
-
-    selected[count++] = id;
-  }
-
-  if(count == 0) {
-    failf(data, "SSL: no supported cipher in list");
-    goto failed;
-  }
-
-  err = SSLSetEnabledCiphers(ssl_ctx, selected, count);
-  if(err != noErr) {
-    failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
-    goto failed;
-  }
-
-  ret = CURLE_OK;
-failed:
-  Curl_safefree(supported);
-  Curl_safefree(selected);
-  return ret;
-}
-
-static void sectransp_session_free(void *sessionid)
-{
-  /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
-     cached session ID inside the Security framework. There is a private
-     function that does this, but I do not want to have to explain to you why I
-     got your application rejected from the App Store due to the use of a
-     private API, so the best we can do is free up our own char array that we
-     created way back in sectransp_connect_step1... */
-  Curl_safefree(sessionid);
-}
-
-static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
-                                        struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
-  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-  const struct curl_blob *ssl_cablob = conn_config->ca_info_blob;
-  const char * const ssl_cafile =
-    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
-    (ssl_cablob ? NULL : conn_config->CAfile);
-  const bool verifypeer = conn_config->verifypeer;
-  char * const ssl_cert = ssl_config->primary.clientcert;
-  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
-  char *ciphers;
-  OSStatus err = noErr;
-  CURLcode result;
-#if CURL_BUILD_MAC
-  int darwinver_maj = 0, darwinver_min = 0;
-
-  DEBUGASSERT(backend);
-
-  CURL_TRC_CF(data, cf, "connect_step1");
-  GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
-#endif /* CURL_BUILD_MAC */
-
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-  if(&SSLCreateContext) {  /* use the newer API if available */
-    if(backend->ssl_ctx)
-      CFRelease(backend->ssl_ctx);
-    backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
-    if(!backend->ssl_ctx) {
-      failf(data, "SSL: could not create a context");
-      return CURLE_OUT_OF_MEMORY;
-    }
-  }
-  else {
-  /* The old ST API does not exist under iOS, so do not compile it: */
-#if CURL_SUPPORT_MAC_10_8
-    if(backend->ssl_ctx)
-      (void)SSLDisposeContext(backend->ssl_ctx);
-    err = SSLNewContext(FALSE, &(backend->ssl_ctx));
-    if(err != noErr) {
-      failf(data, "SSL: could not create a context: OSStatus %d", err);
-      return CURLE_OUT_OF_MEMORY;
-    }
-#endif /* CURL_SUPPORT_MAC_10_8 */
-  }
-#else
-  if(backend->ssl_ctx)
-    (void)SSLDisposeContext(backend->ssl_ctx);
-  err = SSLNewContext(FALSE, &(backend->ssl_ctx));
-  if(err != noErr) {
-    failf(data, "SSL: could not create a context: OSStatus %d", err);
-    return CURLE_OUT_OF_MEMORY;
-  }
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-  backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */
-
-  result = sectransp_set_ssl_version_min_max(data, backend, conn_config);
-  if(result != CURLE_OK)
-    return result;
-
-  if(connssl->alpn) {
-#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
-#ifdef HAVE_BUILTIN_AVAILABLE
-    if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
-#else
-    if(&SSLSetALPNProtocols && &SSLCopyALPNProtocols) {
-#endif
-      struct alpn_proto_buf proto;
-      size_t i;
-      CFStringRef cstr;
-      CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
-                                                       &kCFTypeArrayCallBacks);
-      for(i = 0; i < connssl->alpn->count; ++i) {
-        cstr = CFStringCreateWithCString(NULL, connssl->alpn->entries[i],
-                                         kCFStringEncodingUTF8);
-        if(!cstr)
-          return CURLE_OUT_OF_MEMORY;
-        CFArrayAppendValue(alpnArr, cstr);
-        CFRelease(cstr);
-      }
-      err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr);
-      if(err != noErr)
-        infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d",
-              err);
-      CFRelease(alpnArr);
-      Curl_alpn_to_proto_str(&proto, connssl->alpn);
-      infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
-    }
-#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
-  }
-
-  if(ssl_config->key) {
-    infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
-          "Transport. The private key must be in the Keychain.");
-  }
-
-  if(ssl_cert || ssl_cert_blob) {
-    bool is_cert_data = ssl_cert_blob != NULL;
-    bool is_cert_file = (!is_cert_data) && is_file(ssl_cert);
-    SecIdentityRef cert_and_key = NULL;
-
-    /* User wants to authenticate with a client cert. Look for it. Assume that
-       the user wants to use an identity loaded from the Keychain. If not, try
-       it as a file on disk */
-
-    if(!is_cert_data)
-      err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
-    else
-      err = !noErr;
-    if((err != noErr) && (is_cert_file || is_cert_data)) {
-      if(!ssl_config->cert_type)
-        infof(data, "SSL: Certificate type not set, assuming "
-              "PKCS#12 format.");
-      else if(!strcasecompare(ssl_config->cert_type, "P12")) {
-        failf(data, "SSL: The Security framework only supports "
-              "loading identities that are in PKCS#12 format.");
-        return CURLE_SSL_CERTPROBLEM;
-      }
-
-      err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
-                                       ssl_config->key_passwd,
-                                       &cert_and_key);
-    }
-
-    if(err == noErr && cert_and_key) {
-      SecCertificateRef cert = NULL;
-      CFTypeRef certs_c[1];
-      CFArrayRef certs;
-
-      /* If we found one, print it out: */
-      err = SecIdentityCopyCertificate(cert_and_key, &cert);
-      if(err == noErr) {
-        char *certp;
-        result = CopyCertSubject(data, cert, &certp);
-        if(!result) {
-          infof(data, "Client certificate: %s", certp);
-          free(certp);
-        }
-
-        CFRelease(cert);
-        if(result == CURLE_PEER_FAILED_VERIFICATION)
-          return CURLE_SSL_CERTPROBLEM;
-        if(result)
-          return result;
-      }
-      certs_c[0] = cert_and_key;
-      certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
-                            &kCFTypeArrayCallBacks);
-      err = SSLSetCertificate(backend->ssl_ctx, certs);
-      if(certs)
-        CFRelease(certs);
-      if(err != noErr) {
-        failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err);
-        return CURLE_SSL_CERTPROBLEM;
-      }
-      CFRelease(cert_and_key);
-    }
-    else {
-      const char *cert_showfilename_error =
-        is_cert_data ? "(memory blob)" : ssl_cert;
-
-      switch(err) {
-      case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
-        failf(data, "SSL: Incorrect password for the certificate \"%s\" "
-                    "and its private key.", cert_showfilename_error);
-        break;
-      case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
-        failf(data, "SSL: Couldn't make sense of the data in the "
-                    "certificate \"%s\" and its private key.",
-                    cert_showfilename_error);
-        break;
-      case -25260: /* errSecPassphraseRequired */
-        failf(data, "SSL The certificate \"%s\" requires a password.",
-                    cert_showfilename_error);
-        break;
-      case errSecItemNotFound:
-        failf(data, "SSL: cannot find the certificate \"%s\" and its private "
-                    "key in the Keychain.", cert_showfilename_error);
-        break;
-      default:
-        failf(data, "SSL: cannot load the certificate \"%s\" and its private "
-                    "key: OSStatus %d", cert_showfilename_error, err);
-        break;
-      }
-      return CURLE_SSL_CERTPROBLEM;
-    }
-  }
-
-  /* SSL always tries to verify the peer, this only says whether it should
-   * fail to connect if the verification fails, or if it should continue
-   * anyway. In the latter case the result of the verification is checked with
-   * SSL_get_verify_result() below. */
-#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
-  /* Snow Leopard introduced the SSLSetSessionOption() function, but due to
-     a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
-     works, it does not work as expected under Snow Leopard, Lion or
-     Mountain Lion.
-     So we need to call SSLSetEnableCertVerify() on those older cats in order
-     to disable certificate validation if the user turned that off.
-     (Secure Transport always validates the certificate chain by default.)
-  Note:
-  Darwin 11.x.x is Lion (10.7)
-  Darwin 12.x.x is Mountain Lion (10.8)
-  Darwin 13.x.x is Mavericks (10.9)
-  Darwin 14.x.x is Yosemite (10.10)
-  Darwin 15.x.x is El Capitan (10.11)
-  */
-#if CURL_BUILD_MAC
-  if(&SSLSetSessionOption && darwinver_maj >= 13) {
-#else
-  if(&SSLSetSessionOption) {
-#endif /* CURL_BUILD_MAC */
-    bool break_on_auth = !conn_config->verifypeer ||
-      ssl_cafile || ssl_cablob;
-    err = SSLSetSessionOption(backend->ssl_ctx,
-                              kSSLSessionOptionBreakOnServerAuth,
-                              break_on_auth);
-    if(err != noErr) {
-      failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err);
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-  }
-  else {
-#if CURL_SUPPORT_MAC_10_8
-    err = SSLSetEnableCertVerify(backend->ssl_ctx,
-                                 conn_config->verifypeer ? true : FALSE);
-    if(err != noErr) {
-      failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-#endif /* CURL_SUPPORT_MAC_10_8 */
-  }
-#else
-  err = SSLSetEnableCertVerify(backend->ssl_ctx,
-                               conn_config->verifypeer ? true : FALSE);
-  if(err != noErr) {
-    failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
-
-  if((ssl_cafile || ssl_cablob) && verifypeer) {
-    bool is_cert_data = ssl_cablob != NULL;
-    bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
-
-    if(!(is_cert_file || is_cert_data)) {
-      failf(data, "SSL: cannot load CA certificate file %s",
-            ssl_cafile ? ssl_cafile : "(blob memory)");
-      return CURLE_SSL_CACERT_BADFILE;
-    }
-  }
-
-  /* Configure hostname check. SNI is used if available.
-   * Both hostname check and SNI require SSLSetPeerDomainName().
-   * Also: the verifyhost setting influences SNI usage */
-  if(conn_config->verifyhost) {
-    char *server = connssl->peer.sni ?
-      connssl->peer.sni : connssl->peer.hostname;
-    err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server));
-
-    if(err != noErr) {
-      failf(data, "SSL: SSLSetPeerDomainName() failed: OSStatus %d",
-            err);
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-
-    if(connssl->peer.type != CURL_SSL_PEER_DNS) {
-      infof(data, "WARNING: using IP address, SNI is being disabled by "
-            "the OS.");
-    }
-  }
-  else {
-    infof(data, "WARNING: disabling hostname validation also disables SNI.");
-  }
-
-  ciphers = conn_config->cipher_list;
-  if(ciphers) {
-    result = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
-  }
-  else {
-    result = sectransp_set_default_ciphers(data, backend->ssl_ctx);
-  }
-  if(result != CURLE_OK) {
-    failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. "
-          "Error code: %d", (int)result);
-    return CURLE_SSL_CIPHER;
-  }
-
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
-  /* We want to enable 1/n-1 when using a CBC cipher unless the user
-     specifically does not want us doing that: */
-  if(&SSLSetSessionOption) {
-    SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
-                        !ssl_config->enable_beast);
-    SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
-                      ssl_config->falsestart); /* false start support */
-  }
-#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
-
-  /* Check if there is a cached ID we can/should use here! */
-  if(ssl_config->primary.cache_session) {
-    char *ssl_sessionid;
-    size_t ssl_sessionid_len;
-
-    Curl_ssl_scache_lock(data);
-    ssl_sessionid = Curl_ssl_scache_get_obj(cf, data,
-                                            connssl->peer.scache_key);
-    if(ssl_sessionid) {
-      /* we got a session id, use it! */
-      err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid,
-                         strlen(ssl_sessionid));
-      Curl_ssl_scache_unlock(data);
-      if(err != noErr) {
-        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
-        return CURLE_SSL_CONNECT_ERROR;
-      }
-      else
-        infof(data, "SSL reusing session ID");
-    }
-    /* If there is not one, then let's make one up! This has to be done prior
-       to starting the handshake. */
-    else {
-      ssl_sessionid =
-        aprintf("%s:%d:%d:%s:%d",
-                ssl_cafile ? ssl_cafile : "(blob memory)",
-                verifypeer, conn_config->verifyhost, connssl->peer.hostname,
-                connssl->peer.port);
-      ssl_sessionid_len = strlen(ssl_sessionid);
-
-      err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
-      if(err != noErr) {
-        Curl_ssl_scache_unlock(data);
-        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
-        return CURLE_SSL_CONNECT_ERROR;
-      }
-
-      /* This is all a bit weird, as we have not handshaked yet.
-       * I hope this backend will go away soon. */
-      result = Curl_ssl_scache_add_obj(cf, data, connssl->peer.scache_key,
-                                      (void *)ssl_sessionid,
-                                      sectransp_session_free);
-      Curl_ssl_scache_unlock(data);
-      if(result)
-        return result;
-    }
-  }
-
-  err = SSLSetIOFuncs(backend->ssl_ctx,
-                      sectransp_bio_cf_in_read,
-                      sectransp_bio_cf_out_write);
-  if(err != noErr) {
-    failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-
-  err = SSLSetConnection(backend->ssl_ctx, cf);
-  if(err != noErr) {
-    failf(data, "SSL: SSLSetConnection() failed: %d", err);
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-
-  connssl->connecting_state = ssl_connect_2;
-  return CURLE_OK;
-}
-
-static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
-{
-  char *sep_start, *sep_end, *cert_start, *cert_end;
-  size_t i, j, err;
-  size_t len;
-  char *b64;
-
-  /* Jump through the separators at the beginning of the certificate. */
-  sep_start = strstr(in, "-----");
-  if(!sep_start)
-    return 0;
-  cert_start = strstr(sep_start + 1, "-----");
-  if(!cert_start)
-    return -1;
-
-  cert_start += 5;
-
-  /* Find separator after the end of the certificate. */
-  cert_end = strstr(cert_start, "-----");
-  if(!cert_end)
-    return -1;
-
-  sep_end = strstr(cert_end + 1, "-----");
-  if(!sep_end)
-    return -1;
-  sep_end += 5;
-
-  len = cert_end - cert_start;
-  b64 = malloc(len + 1);
-  if(!b64)
-    return -1;
-
-  /* Create base64 string without linefeeds. */
-  for(i = 0, j = 0; i < len; i++) {
-    if(cert_start[i] != '\r' && cert_start[i] != '\n')
-      b64[j++] = cert_start[i];
-  }
-  b64[j] = '\0';
-
-  err = curlx_base64_decode((const char *)b64, out, outlen);
-  free(b64);
-  if(err) {
-    free(*out);
-    return -1;
-  }
-
-  return sep_end - in;
-}
-
-#define MAX_CERTS_SIZE (50*1024*1024) /* arbitrary - to catch mistakes */
-
-static int read_cert(const char *file, unsigned char **out, size_t *outlen)
-{
-  int fd;
-  ssize_t n;
-  unsigned char buf[512];
-  struct dynbuf certs;
-
-  curlx_dyn_init(&certs, MAX_CERTS_SIZE);
-
-  fd = open(file, 0);
-  if(fd < 0)
-    return -1;
-
-  for(;;) {
-    n = read(fd, buf, sizeof(buf));
-    if(!n)
-      break;
-    if(n < 0) {
-      close(fd);
-      curlx_dyn_free(&certs);
-      return -1;
-    }
-    if(curlx_dyn_addn(&certs, buf, n)) {
-      close(fd);
-      return -1;
-    }
-  }
-  close(fd);
-
-  *out = curlx_dyn_uptr(&certs);
-  *outlen = curlx_dyn_len(&certs);
-
-  return 0;
-}
-
-static CURLcode append_cert_to_array(struct Curl_easy *data,
-                                     const unsigned char *buf, size_t buflen,
-                                     CFMutableArrayRef array)
-{
-    char *certp;
-    CURLcode result;
-    SecCertificateRef cacert;
-    CFDataRef certdata;
-
-    certdata = CFDataCreate(kCFAllocatorDefault, buf, (CFIndex)buflen);
-    if(!certdata) {
-      failf(data, "SSL: failed to allocate array for CA certificate");
-      return CURLE_OUT_OF_MEMORY;
-    }
-
-    cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
-    CFRelease(certdata);
-    if(!cacert) {
-      failf(data, "SSL: failed to create SecCertificate from CA certificate");
-      return CURLE_SSL_CACERT_BADFILE;
-    }
-
-    /* Check if cacert is valid. */
-    result = CopyCertSubject(data, cacert, &certp);
-    switch(result) {
-      case CURLE_OK:
-        break;
-      case CURLE_PEER_FAILED_VERIFICATION:
-        CFRelease(cacert);
-        return CURLE_SSL_CACERT_BADFILE;
-      case CURLE_OUT_OF_MEMORY:
-      default:
-        CFRelease(cacert);
-        return result;
-    }
-    free(certp);
-
-    CFArrayAppendValue(array, cacert);
-    CFRelease(cacert);
-
-    return CURLE_OK;
-}
-
-static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
-                                struct Curl_easy *data,
-                                const unsigned char *certbuf, size_t buflen,
-                                SSLContextRef ctx)
-{
-  int n = 0;
-  CURLcode rc;
-  long res;
-  unsigned char *der;
-  size_t derlen, offset = 0;
-  OSStatus ret;
-  SecTrustResultType trust_eval;
-  CFMutableArrayRef array = NULL;
-  SecTrustRef trust = NULL;
-  CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
-  (void)cf;
-  /*
-   * Certbuf now contains the contents of the certificate file, which can be
-   * - a single DER certificate,
-   * - a single PEM certificate or
-   * - a bunch of PEM certificates (certificate bundle).
-   *
-   * Go through certbuf, and convert any PEM certificate in it into DER
-   * format.
-   */
-  array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-  if(!array) {
-    failf(data, "SSL: out of memory creating CA certificate array");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-
-  while(offset < buflen) {
-    n++;
-
-    /*
-     * Check if the certificate is in PEM format, and convert it to DER. If
-     * this fails, we assume the certificate is in DER format.
-     */
-    res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
-    if(res < 0) {
-      failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
-            n, offset);
-      result = CURLE_SSL_CACERT_BADFILE;
-      goto out;
-    }
-    offset += res;
-
-    if(res == 0 && offset == 0) {
-      /* This is not a PEM file, probably a certificate in DER format. */
-      rc = append_cert_to_array(data, certbuf, buflen, array);
-      if(rc != CURLE_OK) {
-        CURL_TRC_CF(data, cf, "append_cert for CA failed");
-        result = rc;
-        goto out;
-      }
-      break;
-    }
-    else if(res == 0) {
-      /* No more certificates in the bundle. */
-      break;
-    }
-
-    rc = append_cert_to_array(data, der, derlen, array);
-    free(der);
-    if(rc != CURLE_OK) {
-      CURL_TRC_CF(data, cf, "append_cert for CA failed");
-      result = rc;
-      goto out;
-    }
-  }
-
-  ret = SSLCopyPeerTrust(ctx, &trust);
-  if(!trust) {
-    failf(data, "SSL: error getting certificate chain");
-    goto out;
-  }
-  else if(ret != noErr) {
-    failf(data, "SSLCopyPeerTrust() returned error %d", ret);
-    goto out;
-  }
-
-  CURL_TRC_CF(data, cf, "setting %d trust anchors", n);
-  ret = SecTrustSetAnchorCertificates(trust, array);
-  if(ret != noErr) {
-    failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
-    goto out;
-  }
-  ret = SecTrustSetAnchorCertificatesOnly(trust, TRUE);
-  if(ret != noErr) {
-    failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret);
-    goto out;
-  }
-
-  trust_eval = 0;
-  ret = SecTrustEvaluate(trust, &trust_eval);
-  if(ret != noErr) {
-    failf(data, "SecTrustEvaluate() returned error %d", ret);
-    goto out;
-  }
-
-  switch(trust_eval) {
-    case kSecTrustResultUnspecified:
-      /* what does this really mean? */
-      CURL_TRC_CF(data, cf, "trust result: Unspecified");
-      result = CURLE_OK;
-      goto out;
-    case kSecTrustResultProceed:
-      CURL_TRC_CF(data, cf, "trust result: Proceed");
-      result = CURLE_OK;
-      goto out;
-
-    case kSecTrustResultRecoverableTrustFailure:
-      failf(data, "SSL: peer not verified:  RecoverableTrustFailure");
-      goto out;
-    case kSecTrustResultDeny:
-      failf(data, "SSL: peer not verified:  Deny");
-      goto out;
-    default:
-      failf(data, "SSL: perr not verified: result=%d", trust_eval);
-      goto out;
-  }
-
-out:
-  if(trust)
-    CFRelease(trust);
-  if(array)
-    CFRelease(array);
-  return result;
-}
-
-static CURLcode verify_cert(struct Curl_cfilter *cf,
-                            struct Curl_easy *data, const char *cafile,
-                            const struct curl_blob *ca_info_blob,
-                            SSLContextRef ctx)
-{
-  CURLcode result;
-  unsigned char *certbuf;
-  size_t buflen;
-  bool free_certbuf = FALSE;
-
-  if(ca_info_blob) {
-    CURL_TRC_CF(data, cf, "verify_peer, CA from config blob");
-    certbuf = ca_info_blob->data;
-    buflen = ca_info_blob->len;
-  }
-  else if(cafile) {
-    CURL_TRC_CF(data, cf, "verify_peer, CA from file '%s'", cafile);
-    if(read_cert(cafile, &certbuf, &buflen) < 0) {
-      failf(data, "SSL: failed to read or invalid CA certificate");
-      return CURLE_SSL_CACERT_BADFILE;
-    }
-    free_certbuf = TRUE;
-  }
-  else
-    return CURLE_SSL_CACERT_BADFILE;
-
-  result = verify_cert_buf(cf, data, certbuf, buflen, ctx);
-  if(free_certbuf)
-    free(certbuf);
-  return result;
-}
-
-
-#ifdef SECTRANSP_PINNEDPUBKEY
-static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
-                                    SSLContextRef ctx,
-                                    const char *pinnedpubkey)
-{  /* Scratch */
-  size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24;
-  const unsigned char *pubkey = NULL;
-  unsigned char *realpubkey = NULL;
-  const unsigned char *spkiHeader = NULL;
-  CFDataRef publicKeyBits = NULL;
-
-  /* Result is returned to caller */
-  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-
-  /* if a path was not specified, do not pin */
-  if(!pinnedpubkey)
-    return CURLE_OK;
-
-
-  if(!ctx)
-    return result;
-
-  do {
-    SecTrustRef trust;
-    OSStatus ret;
-    SecKeyRef keyRef;
-
-    ret = SSLCopyPeerTrust(ctx, &trust);
-    if(ret != noErr || !trust)
-      break;
-
-    keyRef = SecTrustCopyPublicKey(trust);
-    CFRelease(trust);
-    if(!keyRef)
-      break;
-
-#ifdef SECTRANSP_PINNEDPUBKEY_V1
-
-    publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL);
-    CFRelease(keyRef);
-    if(!publicKeyBits)
-      break;
-
-#elif SECTRANSP_PINNEDPUBKEY_V2
-
-    {
-      OSStatus success;
-      success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
-                              &publicKeyBits);
-      CFRelease(keyRef);
-      if(success != errSecSuccess || !publicKeyBits)
-        break;
-    }
-
-#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
-
-    pubkeylen = (size_t)CFDataGetLength(publicKeyBits);
-    pubkey = (const unsigned char *)CFDataGetBytePtr(publicKeyBits);
-
-    switch(pubkeylen) {
-      case 526:
-        /* 4096 bit RSA pubkeylen == 526 */
-        spkiHeader = rsa4096SpkiHeader;
-        break;
-      case 270:
-        /* 2048 bit RSA pubkeylen == 270 */
-        spkiHeader = rsa2048SpkiHeader;
-        break;
-#ifdef SECTRANSP_PINNEDPUBKEY_V1
-      case 65:
-        /* ecDSA secp256r1 pubkeylen == 65 */
-        spkiHeader = ecDsaSecp256r1SpkiHeader;
-        spkiHeaderLength = 26;
-        break;
-      case 97:
-        /* ecDSA secp384r1 pubkeylen == 97 */
-        spkiHeader = ecDsaSecp384r1SpkiHeader;
-        spkiHeaderLength = 23;
-        break;
-      default:
-        infof(data, "SSL: unhandled public key length: %zu", pubkeylen);
-#elif SECTRANSP_PINNEDPUBKEY_V2
-      default:
-        /* ecDSA secp256r1 pubkeylen == 91 header already included?
-         * ecDSA secp384r1 header already included too
-         * we assume rest of algorithms do same, so do nothing
-         */
-        result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey,
-                                    pubkeylen);
-#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
-        continue; /* break from loop */
-    }
-
-    realpubkeylen = pubkeylen + spkiHeaderLength;
-    realpubkey = malloc(realpubkeylen);
-    if(!realpubkey)
-      break;
-
-    memcpy(realpubkey, spkiHeader, spkiHeaderLength);
-    memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen);
-
-    result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey,
-                                  realpubkeylen);
-
-  } while(0);
-
-  Curl_safefree(realpubkey);
-  if(publicKeyBits)
-    CFRelease(publicKeyBits);
-
-  return result;
-}
-#endif /* SECTRANSP_PINNEDPUBKEY */
-
-static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
-                                        struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
-  OSStatus err;
-  SSLCipherSuite cipher;
-  SSLProtocol protocol = 0;
-
-  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state);
-  DEBUGASSERT(backend);
-  CURL_TRC_CF(data, cf, "connect_step2");
-
-  /* Here goes nothing: */
-check_handshake:
-  connssl->io_need = CURL_SSL_IO_NEED_NONE;
-  err = SSLHandshake(backend->ssl_ctx);
-
-  if(err != noErr) {
-    switch(err) {
-      case errSSLWouldBlock:  /* they are not done with us yet */
-        connssl->io_need = backend->ssl_direction ?
-            CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
-        return CURLE_OK;
-
-      /* The below is errSSLServerAuthCompleted; it is not defined in
-        Leopard's headers */
-      case -9841:
-        if((conn_config->CAfile || conn_config->ca_info_blob) &&
-           conn_config->verifypeer) {
-          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
-                                        conn_config->ca_info_blob,
-                                        backend->ssl_ctx);
-          if(result)
-            return result;
-        }
-        /* the documentation says we need to call SSLHandshake() again */
-        goto check_handshake;
-
-      /* Problem with encrypt / decrypt */
-      case errSSLPeerDecodeError:
-        failf(data, "Decode failed");
-        break;
-      case errSSLDecryptionFail:
-      case errSSLPeerDecryptionFail:
-        failf(data, "Decryption failed");
-        break;
-      case errSSLPeerDecryptError:
-        failf(data, "A decryption error occurred");
-        break;
-      case errSSLBadCipherSuite:
-        failf(data, "A bad SSL cipher suite was encountered");
-        break;
-      case errSSLCrypto:
-        failf(data, "An underlying cryptographic error was encountered");
-        break;
-#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
-      case errSSLWeakPeerEphemeralDHKey:
-        failf(data, "Indicates a weak ephemeral Diffie-Hellman key");
-        break;
-#endif
-
-      /* Problem with the message record validation */
-      case errSSLBadRecordMac:
-      case errSSLPeerBadRecordMac:
-        failf(data, "A record with a bad message authentication code (MAC) "
-                    "was encountered");
-        break;
-      case errSSLRecordOverflow:
-      case errSSLPeerRecordOverflow:
-        failf(data, "A record overflow occurred");
-        break;
-
-      /* Problem with zlib decompression */
-      case errSSLPeerDecompressFail:
-        failf(data, "Decompression failed");
-        break;
-
-      /* Problem with access */
-      case errSSLPeerAccessDenied:
-        failf(data, "Access was denied");
-        break;
-      case errSSLPeerInsufficientSecurity:
-        failf(data, "There is insufficient security for this operation");
-        break;
-
-      /* These are all certificate problems with the server: */
-      case errSSLXCertChainInvalid:
-        failf(data, "SSL certificate problem: Invalid certificate chain");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case errSSLUnknownRootCert:
-        failf(data, "SSL certificate problem: Untrusted root certificate");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case errSSLNoRootCert:
-        failf(data, "SSL certificate problem: No root certificate");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case errSSLCertNotYetValid:
-        failf(data, "SSL certificate problem: The certificate chain had a "
-                    "certificate that is not yet valid");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case errSSLCertExpired:
-      case errSSLPeerCertExpired:
-        failf(data, "SSL certificate problem: Certificate chain had an "
-              "expired certificate");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case errSSLBadCert:
-      case errSSLPeerBadCert:
-        failf(data, "SSL certificate problem: Couldn't understand the server "
-              "certificate format");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case errSSLPeerUnsupportedCert:
-        failf(data, "SSL certificate problem: An unsupported certificate "
-                    "format was encountered");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case errSSLPeerCertRevoked:
-        failf(data, "SSL certificate problem: The certificate was revoked");
-        return CURLE_PEER_FAILED_VERIFICATION;
-      case errSSLPeerCertUnknown:
-        failf(data, "SSL certificate problem: The certificate is unknown");
-        return CURLE_PEER_FAILED_VERIFICATION;
-
-      /* These are all certificate problems with the client: */
-      case errSecAuthFailed:
-        failf(data, "SSL authentication failed");
-        break;
-      case errSSLPeerHandshakeFail:
-        failf(data, "SSL peer handshake failed, the server most likely "
-              "requires a client certificate to connect");
-        break;
-      case errSSLPeerUnknownCA:
-        failf(data, "SSL server rejected the client certificate due to "
-              "the certificate being signed by an unknown certificate "
-              "authority");
-        break;
-
-      /* This error is raised if the server's cert did not match the server's
-         hostname: */
-      case errSSLHostNameMismatch:
-        failf(data, "SSL certificate peer verification failed, the "
-              "certificate did not match \"%s\"\n", connssl->peer.dispname);
-        return CURLE_PEER_FAILED_VERIFICATION;
-
-      /* Problem with SSL / TLS negotiation */
-      case errSSLNegotiation:
-        failf(data, "Could not negotiate an SSL cipher suite with the server");
-        break;
-      case errSSLBadConfiguration:
-        failf(data, "A configuration error occurred");
-        break;
-      case errSSLProtocol:
-        failf(data, "SSL protocol error");
-        break;
-      case errSSLPeerProtocolVersion:
-        failf(data, "A bad protocol version was encountered");
-        break;
-      case errSSLPeerNoRenegotiation:
-        failf(data, "No renegotiation is allowed");
-        break;
-
-      /* Generic handshake errors: */
-      case errSSLConnectionRefused:
-        failf(data, "Server dropped the connection during the SSL handshake");
-        break;
-      case errSSLClosedAbort:
-        failf(data, "Server aborted the SSL handshake");
-        break;
-      case errSSLClosedGraceful:
-        failf(data, "The connection closed gracefully");
-        break;
-      case errSSLClosedNoNotify:
-        failf(data, "The server closed the session with no notification");
-        break;
-      /* Sometimes paramErr happens with buggy ciphers: */
-      case paramErr:
-      case errSSLInternal:
-      case errSSLPeerInternalError:
-        failf(data, "Internal SSL engine error encountered during the "
-              "SSL handshake");
-        break;
-      case errSSLFatalAlert:
-        failf(data, "Fatal SSL engine error encountered during the SSL "
-              "handshake");
-        break;
-      /* Unclassified error */
-      case errSSLBufferOverflow:
-        failf(data, "An insufficient buffer was provided");
-        break;
-      case errSSLIllegalParam:
-        failf(data, "An illegal parameter was encountered");
-        break;
-      case errSSLModuleAttach:
-        failf(data, "Module attach failure");
-        break;
-      case errSSLSessionNotFound:
-        failf(data, "An attempt to restore an unknown session failed");
-        break;
-      case errSSLPeerExportRestriction:
-        failf(data, "An export restriction occurred");
-        break;
-      case errSSLPeerUserCancelled:
-        failf(data, "The user canceled the operation");
-        break;
-      case errSSLPeerUnexpectedMsg:
-        failf(data, "Peer rejected unexpected message");
-        break;
-#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
-      /* Treating non-fatal error as fatal like before */
-      case errSSLClientHelloReceived:
-        failf(data, "A non-fatal result for providing a server name "
-                    "indication");
-        break;
-#endif
-
-      /* Error codes defined in the enum but should never be returned.
-         We list them here just in case. */
-#if CURL_BUILD_MAC_10_6
-      /* Only returned when kSSLSessionOptionBreakOnCertRequested is set */
-      case errSSLClientCertRequested:
-        failf(data, "Server requested a client certificate during the "
-              "handshake");
-        return CURLE_SSL_CLIENTCERT;
-#endif
-#if CURL_BUILD_MAC_10_9
-      /* Alias for errSSLLast, end of error range */
-      case errSSLUnexpectedRecord:
-        failf(data, "Unexpected (skipped) record in DTLS");
-        break;
-#endif
-      default:
-        /* May also return codes listed in Security Framework Result Codes */
-        failf(data, "Unknown SSL protocol error in connection to %s:%d",
-              connssl->peer.hostname, err);
-        break;
-    }
-    return CURLE_SSL_CONNECT_ERROR;
-  }
-  else {
-    char cipher_str[64];
-    /* we have been connected fine, we are not waiting for anything else. */
-    connssl->connecting_state = ssl_connect_3;
-
-#ifdef SECTRANSP_PINNEDPUBKEY
-    if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
-      CURLcode result =
-        pkp_pin_peer_pubkey(data, backend->ssl_ctx,
-                            data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
-      if(result) {
-        failf(data, "SSL: public key does not match pinned public key");
-        return result;
-      }
-    }
-#endif /* SECTRANSP_PINNEDPUBKEY */
-
-    /* Informational message */
-    (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher);
-    (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
-
-    sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str,
-                                   sizeof(cipher_str), TRUE);
-    switch(protocol) {
-      case kSSLProtocol2:
-        infof(data, "SSL 2.0 connection using %s", cipher_str);
-        break;
-      case kSSLProtocol3:
-        infof(data, "SSL 3.0 connection using %s", cipher_str);
-        break;
-      case kTLSProtocol1:
-        infof(data, "TLS 1.0 connection using %s", cipher_str);
-        break;
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-      case kTLSProtocol11:
-        infof(data, "TLS 1.1 connection using %s", cipher_str);
-        break;
-      case kTLSProtocol12:
-        infof(data, "TLS 1.2 connection using %s", cipher_str);
-        break;
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
-      case kTLSProtocol13:
-        infof(data, "TLS 1.3 connection using %s", cipher_str);
-        break;
-#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
-      default:
-        infof(data, "Unknown protocol connection");
-        break;
-    }
-
-    if(connssl->alpn) {
-#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
-#ifdef HAVE_BUILTIN_AVAILABLE
-      if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
-#else
-      if(&SSLSetALPNProtocols && &SSLCopyALPNProtocols) {
-#endif
-        CFArrayRef alpnArr = NULL;
-        CFStringRef chosenProtocol = NULL;
-        err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr);
-
-        if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1)
-          chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0);
-
-#ifdef USE_HTTP2
-        if(chosenProtocol &&
-           !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) {
-          cf->conn->alpn = CURL_HTTP_VERSION_2;
-        }
-        else
-#endif
-        if(chosenProtocol &&
-           !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) {
-          cf->conn->alpn = CURL_HTTP_VERSION_1_1;
-        }
-        else
-          infof(data, VTLS_INFOF_NO_ALPN);
-
-        /* chosenProtocol is a reference to the string within alpnArr
-           and does not need to be freed separately */
-        if(alpnArr)
-          CFRelease(alpnArr);
-      }
-#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
-    }
-
-    return CURLE_OK;
-  }
-}
-
-static CURLcode
-add_cert_to_certinfo(struct Curl_easy *data,
-                     const SecCertificateRef server_cert,
-                     int idx)
-{
-  CURLcode result = CURLE_OK;
-  const char *beg;
-  const char *end;
-  CFDataRef cert_data = SecCertificateCopyData(server_cert);
-
-  if(!cert_data)
-    return CURLE_PEER_FAILED_VERIFICATION;
-
-  beg = (const char *)CFDataGetBytePtr(cert_data);
-  end = beg + CFDataGetLength(cert_data);
-  result = Curl_extract_certinfo(data, idx, beg, end);
-  CFRelease(cert_data);
-  return result;
-}
-
-static CURLcode
-collect_server_cert_single(struct Curl_cfilter *cf, struct Curl_easy *data,
-                           const SecCertificateRef server_cert,
-                           CFIndex idx)
-{
-  CURLcode result = CURLE_OK;
-  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-  if(data->set.verbose) {
-    char *certp;
-    result = CopyCertSubject(data, server_cert, &certp);
-    if(!result) {
-      infof(data, "Server certificate: %s", certp);
-      free(certp);
-    }
-  }
-#endif
-  if(ssl_config->certinfo)
-    result = add_cert_to_certinfo(data, server_cert, (int)idx);
-  return result;
-}
-
-/* This should be called during step3 of the connection at the earliest */
-static CURLcode collect_server_cert(struct Curl_cfilter *cf,
-                                    struct Curl_easy *data)
-{
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-  const bool show_verbose_server_cert = data->set.verbose;
-#else
-  const bool show_verbose_server_cert = FALSE;
-#endif
-  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-  CURLcode result = ssl_config->certinfo ?
-    CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  CFArrayRef server_certs = NULL;
-  SecCertificateRef server_cert;
-  OSStatus err;
-  CFIndex i, count;
-  SecTrustRef trust = NULL;
-
-  DEBUGASSERT(backend);
-
-  if(!show_verbose_server_cert && !ssl_config->certinfo)
-    return CURLE_OK;
-
-  if(!backend->ssl_ctx)
-    return result;
-
-#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
-#if CURL_BUILD_IOS
-#pragma unused(server_certs)
-  err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
-  /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
-     a null trust, so be on guard for that: */
-  if(err == noErr && trust) {
-    count = SecTrustGetCertificateCount(trust);
-    if(ssl_config->certinfo)
-      result = Curl_ssl_init_certinfo(data, (int)count);
-    for(i = 0L ; !result && (i < count) ; i++) {
-      server_cert = SecTrustGetCertificateAtIndex(trust, i);
-      result = collect_server_cert_single(cf, data, server_cert, i);
-    }
-    CFRelease(trust);
-  }
-#else
-  /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
-     The function SecTrustGetCertificateAtIndex() is officially present
-     in Lion, but it is unfortunately also present in Snow Leopard as
-     private API and does not work as expected. So we have to look for
-     a different symbol to make sure this code is only executed under
-     Lion or later. */
-  if(&SecTrustCopyPublicKey) {
-#pragma unused(server_certs)
-    err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
-    /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
-       a null trust, so be on guard for that: */
-    if(err == noErr && trust) {
-      count = SecTrustGetCertificateCount(trust);
-      if(ssl_config->certinfo)
-        result = Curl_ssl_init_certinfo(data, (int)count);
-      for(i = 0L ; !result && (i < count) ; i++) {
-        server_cert = SecTrustGetCertificateAtIndex(trust, i);
-        result = collect_server_cert_single(cf, data, server_cert, i);
-      }
-      CFRelease(trust);
-    }
-  }
-  else {
-#if CURL_SUPPORT_MAC_10_8
-    err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
-    /* Just in case SSLCopyPeerCertificates() returns null too... */
-    if(err == noErr && server_certs) {
-      count = CFArrayGetCount(server_certs);
-      if(ssl_config->certinfo)
-        result = Curl_ssl_init_certinfo(data, (int)count);
-      for(i = 0L ; !result && (i < count) ; i++) {
-        const void *item = CFArrayGetValueAtIndex(server_certs, i);
-        server_cert = (SecCertificateRef)CURL_UNCONST(item);
-        result = collect_server_cert_single(cf, data, server_cert, i);
-      }
-      CFRelease(server_certs);
-    }
-#endif /* CURL_SUPPORT_MAC_10_8 */
-  }
-#endif /* CURL_BUILD_IOS */
-#else
-#pragma unused(trust)
-  err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs);
-  if(err == noErr) {
-    count = CFArrayGetCount(server_certs);
-    if(ssl_config->certinfo)
-      result = Curl_ssl_init_certinfo(data, (int)count);
-    for(i = 0L ; !result && (i < count) ; i++) {
-      const void *item = CFArrayGetValueAtIndex(server_certs, i);
-      server_cert = (SecCertificateRef)CURL_UNCONST(item);
-      result = collect_server_cert_single(cf, data, server_cert, i);
-    }
-    CFRelease(server_certs);
-  }
-#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
-  return result;
-}
-
-static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
-                                        struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  CURLcode result;
-
-  CURL_TRC_CF(data, cf, "connect_step3");
-  /* There is no step 3!
-   * Well, okay, let's collect server certificates, and if verbose mode is on,
-   * let's print the details of the server certificates. */
-  result = collect_server_cert(cf, data);
-  if(result)
-    return result;
-
-  connssl->connecting_state = ssl_connect_done;
-  return CURLE_OK;
-}
-
-static CURLcode sectransp_connect(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  bool *done)
-{
-  CURLcode result;
-  struct ssl_connect_data *connssl = cf->ctx;
-
-  /* check if the connection has already been established */
-  if(ssl_connection_complete == connssl->state) {
-    *done = TRUE;
-    return CURLE_OK;
-  }
-
-  *done = FALSE;
-  connssl->io_need = CURL_SSL_IO_NEED_NONE;
-
-  if(ssl_connect_1 == connssl->connecting_state) {
-    result = sectransp_connect_step1(cf, data);
-    if(result)
-      return result;
-  }
-
-  if(ssl_connect_2 == connssl->connecting_state) {
-    result = sectransp_connect_step2(cf, data);
-    if(result)
-      return result;
-  }
-
-  if(ssl_connect_3 == connssl->connecting_state) {
-    result = sectransp_connect_step3(cf, data);
-    if(result)
-      return result;
-  }
-
-  if(ssl_connect_done == connssl->connecting_state) {
-    CURL_TRC_CF(data, cf, "connected");
-    connssl->state = ssl_connection_complete;
-    *done = TRUE;
-  }
-
-  return CURLE_OK;
-}
-
-static ssize_t sectransp_recv(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              char *buf,
-                              size_t buffersize,
-                              CURLcode *curlcode);
-
-static CURLcode sectransp_shutdown(struct Curl_cfilter *cf,
-                                   struct Curl_easy *data,
-                                   bool send_shutdown, bool *done)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  CURLcode result = CURLE_OK;
-  ssize_t nread = 0;
-  char buf[1024];
-  size_t i;
-
-  DEBUGASSERT(backend);
-  if(!backend->ssl_ctx || cf->shutdown) {
-    *done = TRUE;
-    goto out;
-  }
-
-  connssl->io_need = CURL_SSL_IO_NEED_NONE;
-  *done = FALSE;
-
-  if(send_shutdown && !backend->sent_shutdown) {
-    OSStatus err;
-
-    CURL_TRC_CF(data, cf, "shutdown, send close notify");
-    err = SSLClose(backend->ssl_ctx);
-    switch(err) {
-      case noErr:
-        backend->sent_shutdown = TRUE;
-        break;
-      case errSSLWouldBlock:
-        connssl->io_need = CURL_SSL_IO_NEED_SEND;
-        result = CURLE_OK;
-        goto out;
-      default:
-        CURL_TRC_CF(data, cf, "shutdown, error: %d", (int)err);
-        result = CURLE_SEND_ERROR;
-        goto out;
-    }
-  }
-
-  for(i = 0; i < 10; ++i) {
-    if(!backend->sent_shutdown) {
-      nread = sectransp_recv(cf, data, buf, (int)sizeof(buf), &result);
-    }
-    else {
-      /* We would like to read the close notify from the server using
-       * Secure Transport, however SSLRead() no longer works after we
-       * sent the notify from our side. So, we just read from the
-       * underlying filter and hope it will end. */
-      nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
-    }
-    CURL_TRC_CF(data, cf, "shutdown read -> %zd, %d", nread, result);
-    if(nread <= 0)
-      break;
-  }
-
-  if(nread > 0) {
-    /* still data coming in? */
-    connssl->io_need = CURL_SSL_IO_NEED_RECV;
-  }
-  else if(nread == 0) {
-    /* We got the close notify alert and are done. */
-    CURL_TRC_CF(data, cf, "shutdown done");
-    *done = TRUE;
-  }
-  else if(result == CURLE_AGAIN) {
-    connssl->io_need = CURL_SSL_IO_NEED_RECV;
-    result = CURLE_OK;
-  }
-  else {
-    DEBUGASSERT(result);
-    CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
-  }
-
-out:
-  cf->shutdown = (result || *done);
-  return result;
-}
-
-static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-
-  (void) data;
-
-  DEBUGASSERT(backend);
-
-  if(backend->ssl_ctx) {
-    CURL_TRC_CF(data, cf, "close");
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
-    if(&SSLCreateContext)
-      CFRelease(backend->ssl_ctx);
-#if CURL_SUPPORT_MAC_10_8
-    else
-      (void)SSLDisposeContext(backend->ssl_ctx);
-#endif  /* CURL_SUPPORT_MAC_10_8 */
-#else
-    (void)SSLDisposeContext(backend->ssl_ctx);
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-    backend->ssl_ctx = NULL;
-  }
-}
-
-static size_t sectransp_version(char *buffer, size_t size)
-{
-  return msnprintf(buffer, size, "SecureTransport");
-}
-
-static bool sectransp_data_pending(struct Curl_cfilter *cf,
-                                   const struct Curl_easy *data)
-{
-  const struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  OSStatus err;
-  size_t buffer;
-
-  (void)data;
-  DEBUGASSERT(backend);
-
-  if(backend->ssl_ctx) {  /* SSL is in use */
-    CURL_TRC_CF((struct Curl_easy *)CURL_UNCONST(data), cf, "data_pending");
-    err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
-    if(err == noErr)
-      return buffer > 0UL;
-    return FALSE;
-  }
-  else
-    return FALSE;
-}
-
-static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
-                                 unsigned char *entropy, size_t length)
-{
-  /* arc4random_buf() is not available on cats older than Lion, so let's
-     do this manually for the benefit of the older cats. */
-  size_t i;
-  u_int32_t random_number = 0;
-
-  (void)data;
-
-  for(i = 0 ; i < length ; i++) {
-    if(i % sizeof(u_int32_t) == 0)
-      random_number = arc4random();
-    entropy[i] = random_number & 0xFF;
-    random_number >>= 8;
-  }
-  i = random_number = 0;
-  return CURLE_OK;
-}
-
-static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
-                                    size_t tmplen,
-                                    unsigned char *sha256sum, /* output */
-                                    size_t sha256len)
-{
-  (void)sha256len;
-  assert(sha256len >= CURL_SHA256_DIGEST_LENGTH);
-  (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
-  return CURLE_OK;
-}
-
-static bool sectransp_false_start(void)
-{
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
-  if(&SSLSetSessionOption)
-    return TRUE;
-#endif
-  return FALSE;
-}
-
-static ssize_t sectransp_send(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              const void *mem,
-                              size_t len,
-                              CURLcode *curlcode)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  size_t processed = 0UL;
-  OSStatus err;
-
-  DEBUGASSERT(backend);
-
-  /* The SSLWrite() function works a little differently than expected. The
-     fourth argument (processed) is currently documented in Apple's
-     documentation as: "On return, the length, in bytes, of the data actually
-     written."
-
-     Now, one could interpret that as "written to the socket," but actually,
-     it returns the amount of data that was written to a buffer internal to
-     the SSLContextRef instead. So it is possible for SSLWrite() to return
-     errSSLWouldBlock and a number of bytes "written" because those bytes were
-     encrypted and written to a buffer, not to the socket.
-
-     So if this happens, then we need to keep calling SSLWrite() over and
-     over again with no new data until it quits returning errSSLWouldBlock. */
-
-  /* Do we have buffered data to write from the last time we were called? */
-  if(backend->ssl_write_buffered_length) {
-    /* Write the buffered data: */
-    err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed);
-    switch(err) {
-      case noErr:
-        /* processed is always going to be 0 because we did not write to
-           the buffer, so return how much was written to the socket */
-        processed = backend->ssl_write_buffered_length;
-        backend->ssl_write_buffered_length = 0UL;
-        break;
-      case errSSLWouldBlock: /* argh, try again */
-        *curlcode = CURLE_AGAIN;
-        return -1L;
-      default:
-        failf(data, "SSLWrite() returned error %d", err);
-        *curlcode = CURLE_SEND_ERROR;
-        return -1L;
-    }
-  }
-  else {
-    /* We have got new data to write: */
-    err = SSLWrite(backend->ssl_ctx, mem, len, &processed);
-    if(err != noErr) {
-      switch(err) {
-        case errSSLWouldBlock:
-          /* Data was buffered but not sent, we have to tell the caller
-             to try sending again, and remember how much was buffered */
-          backend->ssl_write_buffered_length = len;
-          *curlcode = CURLE_AGAIN;
-          return -1L;
-        default:
-          failf(data, "SSLWrite() returned error %d", err);
-          *curlcode = CURLE_SEND_ERROR;
-          return -1L;
-      }
-    }
-  }
-  return (ssize_t)processed;
-}
-
-static ssize_t sectransp_recv(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              char *buf,
-                              size_t buffersize,
-                              CURLcode *curlcode)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
-  size_t processed = 0UL;
-  OSStatus err;
-
-  DEBUGASSERT(backend);
-
-again:
-  *curlcode = CURLE_OK;
-  err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed);
-
-  if(err != noErr) {
-    switch(err) {
-      case errSSLWouldBlock:  /* return how much we read (if anything) */
-        if(processed) {
-          return (ssize_t)processed;
-        }
-        *curlcode = CURLE_AGAIN;
-        return -1L;
-
-      /* errSSLClosedGraceful - server gracefully shut down the SSL session
-         errSSLClosedNoNotify - server hung up on us instead of sending a
-           closure alert notice, read() is returning 0
-         Either way, inform the caller that the server disconnected. */
-      case errSSLClosedGraceful:
-      case errSSLClosedNoNotify:
-        *curlcode = CURLE_OK;
-        return 0;
-
-        /* The below is errSSLPeerAuthCompleted; it is not defined in
-           Leopard's headers */
-      case -9841:
-        if((conn_config->CAfile || conn_config->ca_info_blob) &&
-           conn_config->verifypeer) {
-          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
-                                        conn_config->ca_info_blob,
-                                        backend->ssl_ctx);
-          if(result) {
-            *curlcode = result;
-            return -1;
-          }
-        }
-        goto again;
-      default:
-        failf(data, "SSLRead() return error %d", err);
-        *curlcode = CURLE_RECV_ERROR;
-        return -1L;
-    }
-  }
-  return (ssize_t)processed;
-}
-
-static void *sectransp_get_internals(struct ssl_connect_data *connssl,
-                                     CURLINFO info UNUSED_PARAM)
-{
-  struct st_ssl_backend_data *backend =
-    (struct st_ssl_backend_data *)connssl->backend;
-  (void)info;
-  DEBUGASSERT(backend);
-  return backend->ssl_ctx;
-}
-
-const struct Curl_ssl Curl_ssl_sectransp = {
-  { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
-
-  SSLSUPP_CAINFO_BLOB |
-  SSLSUPP_CERTINFO |
-#ifdef SECTRANSP_PINNEDPUBKEY
-  SSLSUPP_PINNEDPUBKEY |
-#endif /* SECTRANSP_PINNEDPUBKEY */
-  SSLSUPP_HTTPS_PROXY |
-  SSLSUPP_CIPHER_LIST,
-
-  sizeof(struct st_ssl_backend_data),
-
-  NULL,                               /* init */
-  NULL,                               /* cleanup */
-  sectransp_version,                  /* version */
-  sectransp_shutdown,                 /* shutdown */
-  sectransp_data_pending,             /* data_pending */
-  sectransp_random,                   /* random */
-  NULL,                               /* cert_status_request */
-  sectransp_connect,                  /* connect */
-  Curl_ssl_adjust_pollset,            /* adjust_pollset */
-  sectransp_get_internals,            /* get_internals */
-  sectransp_close,                    /* close_one */
-  NULL,                               /* close_all */
-  NULL,                               /* set_engine */
-  NULL,                               /* set_engine_default */
-  NULL,                               /* engines_list */
-  sectransp_false_start,              /* false_start */
-  sectransp_sha256sum,                /* sha256sum */
-  sectransp_recv,                     /* recv decrypted data */
-  sectransp_send,                     /* send data to encrypt */
-  NULL,                               /* get_channel_binding */
-};
-
-#if defined(__GNUC__) && defined(__APPLE__)
-#pragma GCC diagnostic pop
-#endif
-
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#endif /* USE_SECTRANSP */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index c6fb60d..db4e573 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -43,9 +43,6 @@
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
@@ -61,9 +58,7 @@
 #include "gtls.h"           /* GnuTLS versions */
 #include "wolfssl.h"        /* wolfSSL versions */
 #include "schannel.h"       /* Schannel SSPI version */
-#include "sectransp.h"      /* Secure Transport (Darwin) version */
 #include "mbedtls.h"        /* mbedTLS versions */
-#include "bearssl.h"        /* BearSSL versions */
 #include "rustls.h"         /* Rustls versions */
 
 #include "../slist.h"
@@ -212,12 +207,12 @@
      !Curl_timestrcmp(c1->username, c2->username) &&
      !Curl_timestrcmp(c1->password, c2->password) &&
 #endif
-     strcasecompare(c1->cipher_list, c2->cipher_list) &&
-     strcasecompare(c1->cipher_list13, c2->cipher_list13) &&
-     strcasecompare(c1->curves, c2->curves) &&
-     strcasecompare(c1->signature_algorithms, c2->signature_algorithms) &&
-     strcasecompare(c1->CRLfile, c2->CRLfile) &&
-     strcasecompare(c1->pinned_key, c2->pinned_key))
+     curl_strequal(c1->cipher_list, c2->cipher_list) &&
+     curl_strequal(c1->cipher_list13, c2->cipher_list13) &&
+     curl_strequal(c1->curves, c2->curves) &&
+     curl_strequal(c1->signature_algorithms, c2->signature_algorithms) &&
+     curl_strequal(c1->CRLfile, c2->CRLfile) &&
+     curl_strequal(c1->pinned_key, c2->pinned_key))
     return TRUE;
 
   return FALSE;
@@ -491,7 +486,7 @@
 }
 
 CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
-                                       struct dynbuf *binding)
+                                      struct dynbuf *binding)
 {
   if(Curl_ssl->get_channel_binding)
     return Curl_ssl->get_channel_binding(data, sockindex, binding);
@@ -505,7 +500,7 @@
 }
 
 void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
-                              struct easy_pollset *ps)
+                             struct easy_pollset *ps)
 {
   struct ssl_connect_data *connssl = cf->ctx;
 
@@ -878,16 +873,6 @@
   return FALSE;
 }
 
-/*
- * Check whether the SSL backend supports false start.
- */
-bool Curl_ssl_false_start(void)
-{
-  if(Curl_ssl->false_start)
-    return Curl_ssl->false_start();
-  return FALSE;
-}
-
 static int multissl_init(void)
 {
   if(multissl_setup(NULL))
@@ -906,8 +891,8 @@
 }
 
 static void multissl_adjust_pollset(struct Curl_cfilter *cf,
-                                     struct Curl_easy *data,
-                                     struct easy_pollset *ps)
+                                    struct Curl_easy *data,
+                                    struct easy_pollset *ps)
 {
   if(multissl_setup(NULL))
     return;
@@ -929,23 +914,23 @@
   Curl_ssl->close(cf, data);
 }
 
-static ssize_t multissl_recv_plain(struct Curl_cfilter *cf,
-                                   struct Curl_easy *data,
-                                   char *buf, size_t len, CURLcode *code)
+static CURLcode multissl_recv_plain(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    char *buf, size_t len, size_t *pnread)
 {
   if(multissl_setup(NULL))
     return CURLE_FAILED_INIT;
-  return Curl_ssl->recv_plain(cf, data, buf, len, code);
+  return Curl_ssl->recv_plain(cf, data, buf, len, pnread);
 }
 
-static ssize_t multissl_send_plain(struct Curl_cfilter *cf,
-                                   struct Curl_easy *data,
-                                   const void *mem, size_t len,
-                                   CURLcode *code)
+static CURLcode multissl_send_plain(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    const void *mem, size_t len,
+                                    size_t *pnwritten)
 {
   if(multissl_setup(NULL))
     return CURLE_FAILED_INIT;
-  return Curl_ssl->send_plain(cf, data, mem, len, code);
+  return Curl_ssl->send_plain(cf, data, mem, len, pnwritten);
 }
 
 static const struct Curl_ssl Curl_ssl_multi = {
@@ -968,7 +953,6 @@
   NULL,                              /* set_engine */
   NULL,                              /* set_engine_default */
   NULL,                              /* engines_list */
-  NULL,                              /* false_start */
   NULL,                              /* sha256sum */
   multissl_recv_plain,               /* recv decrypted data */
   multissl_send_plain,               /* send data to encrypt */
@@ -988,12 +972,8 @@
   &Curl_ssl_rustls;
 #elif defined(USE_OPENSSL)
   &Curl_ssl_openssl;
-#elif defined(USE_SECTRANSP)
-  &Curl_ssl_sectransp;
 #elif defined(USE_SCHANNEL)
   &Curl_ssl_schannel;
-#elif defined(USE_BEARSSL)
-  &Curl_ssl_bearssl;
 #else
 #error "Missing struct Curl_ssl for selected SSL backend"
 #endif
@@ -1011,15 +991,9 @@
 #if defined(USE_OPENSSL)
   &Curl_ssl_openssl,
 #endif
-#if defined(USE_SECTRANSP)
-  &Curl_ssl_sectransp,
-#endif
 #if defined(USE_SCHANNEL)
   &Curl_ssl_schannel,
 #endif
-#if defined(USE_BEARSSL)
-  &Curl_ssl_bearssl,
-#endif
 #if defined(USE_RUSTLS)
   &Curl_ssl_rustls,
 #endif
@@ -1099,7 +1073,7 @@
   env = curl_getenv("CURL_SSL_BACKEND");
   if(env) {
     for(i = 0; available_backends[i]; i++) {
-      if(strcasecompare(env, available_backends[i]->info.name)) {
+      if(curl_strequal(env, available_backends[i]->info.name)) {
         Curl_ssl = available_backends[i];
         free(env);
         return 0;
@@ -1109,8 +1083,8 @@
 
 #ifdef CURL_DEFAULT_SSL_BACKEND
   for(i = 0; available_backends[i]; i++) {
-    if(strcasecompare(CURL_DEFAULT_SSL_BACKEND,
-                      available_backends[i]->info.name)) {
+    if(curl_strequal(CURL_DEFAULT_SSL_BACKEND,
+                     available_backends[i]->info.name)) {
       Curl_ssl = available_backends[i];
       free(env);
       return 0;
@@ -1136,7 +1110,7 @@
 
   if(Curl_ssl != &Curl_ssl_multi)
     return id == Curl_ssl->info.id ||
-           (name && strcasecompare(name, Curl_ssl->info.name)) ?
+           (name && curl_strequal(name, Curl_ssl->info.name)) ?
            CURLSSLSET_OK :
 #if defined(CURL_WITH_MULTI_SSL)
            CURLSSLSET_TOO_LATE;
@@ -1146,7 +1120,7 @@
 
   for(i = 0; available_backends[i]; i++) {
     if(available_backends[i]->info.id == id ||
-       (name && strcasecompare(available_backends[i]->info.name, name))) {
+       (name && curl_strequal(available_backends[i]->info.name, name))) {
       multissl_setup(available_backends[i]);
       return CURLSSLSET_OK;
     }
@@ -1372,7 +1346,7 @@
                                      const void *buf, size_t blen)
 {
   struct ssl_connect_data *connssl = cf->ctx;
-  ssize_t nwritten = 0;
+  size_t nwritten = 0;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_await);
@@ -1380,10 +1354,10 @@
   if(blen) {
     if(blen > connssl->earlydata_max)
       blen = connssl->earlydata_max;
-    nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
+    result = Curl_bufq_write(&connssl->earlydata, buf, blen, &nwritten);
     CURL_TRC_CF(data, cf, "ssl_cf_set_earlydata(len=%zu) -> %zd",
                 blen, nwritten);
-    if(nwritten < 0)
+    if(result)
       return result;
   }
   return CURLE_OK;
@@ -1455,29 +1429,26 @@
   return result;
 }
 
-static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
-                           struct Curl_easy *data,
-                           const void *buf, size_t blen,
-                           bool eos, CURLcode *err)
+static CURLcode ssl_cf_send(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            const void *buf, size_t blen,
+                            bool eos, size_t *pnwritten)
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct cf_call_data save;
-  ssize_t nwritten = 0, early_written = 0;
+  CURLcode result = CURLE_OK;
 
   (void)eos;
-  *err = CURLE_OK;
+  *pnwritten = 0;
   CF_DATA_SAVE(save, cf, data);
 
   if(connssl->state == ssl_connection_deferred) {
     bool done = FALSE;
-    *err = ssl_cf_connect_deferred(cf, data, buf, blen, &done);
-    if(*err) {
-      nwritten = -1;
+    result = ssl_cf_connect_deferred(cf, data, buf, blen, &done);
+    if(result)
       goto out;
-    }
     else if(!done) {
-      *err = CURLE_AGAIN;
-      nwritten = -1;
+      result = CURLE_AGAIN;
       goto out;
     }
     DEBUGASSERT(connssl->state == ssl_connection_complete);
@@ -1486,12 +1457,12 @@
   if(connssl->earlydata_skip) {
     if(connssl->earlydata_skip >= blen) {
       connssl->earlydata_skip -= blen;
-      *err = CURLE_OK;
-      nwritten = (ssize_t)blen;
+      result = CURLE_OK;
+      *pnwritten = blen;
       goto out;
     }
     else {
-      early_written = connssl->earlydata_skip;
+      *pnwritten = connssl->earlydata_skip;
       buf = ((const char *)buf) + connssl->earlydata_skip;
       blen -= connssl->earlydata_skip;
       connssl->earlydata_skip = 0;
@@ -1499,56 +1470,45 @@
   }
 
   /* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
-  if(blen > 0)
-    nwritten = connssl->ssl_impl->send_plain(cf, data, buf, blen, err);
-
-  if(nwritten >= 0)
-    nwritten += early_written;
+  if(blen > 0) {
+    size_t nwritten;
+    result = connssl->ssl_impl->send_plain(cf, data, buf, blen, &nwritten);
+    if(!result)
+      *pnwritten += nwritten;
+  }
 
 out:
   CF_DATA_RESTORE(cf, save);
-  return nwritten;
+  return result;
 }
 
-static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
-                           struct Curl_easy *data, char *buf, size_t len,
-                           CURLcode *err)
+static CURLcode ssl_cf_recv(struct Curl_cfilter *cf,
+                            struct Curl_easy *data, char *buf, size_t len,
+                            size_t *pnread)
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct cf_call_data save;
-  ssize_t nread;
+  CURLcode result = CURLE_OK;
 
   CF_DATA_SAVE(save, cf, data);
-  *err = CURLE_OK;
+  *pnread = 0;
   if(connssl->state == ssl_connection_deferred) {
     bool done = FALSE;
-    *err = ssl_cf_connect_deferred(cf, data, NULL, 0, &done);
-    if(*err) {
-      nread = -1;
+    result = ssl_cf_connect_deferred(cf, data, NULL, 0, &done);
+    if(result)
       goto out;
-    }
     else if(!done) {
-      *err = CURLE_AGAIN;
-      nread = -1;
+      result = CURLE_AGAIN;
       goto out;
     }
     DEBUGASSERT(connssl->state == ssl_connection_complete);
   }
 
-  nread = connssl->ssl_impl->recv_plain(cf, data, buf, len, err);
-  if(nread > 0) {
-    DEBUGASSERT((size_t)nread <= len);
-  }
-  else if(nread == 0) {
-    /* eof */
-    *err = CURLE_OK;
-  }
+  result = connssl->ssl_impl->recv_plain(cf, data, buf, len, pnread);
 
 out:
-  CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
-              nread, *err);
   CF_DATA_RESTORE(cf, save);
-  return nread;
+  return result;
 }
 
 static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
@@ -1598,6 +1558,18 @@
       *when = connssl->handshake_done;
     return CURLE_OK;
   }
+  case CF_QUERY_SSL_INFO:
+  case CF_QUERY_SSL_CTX_INFO: {
+    struct curl_tlssessioninfo *info = pres2;
+    struct cf_call_data save;
+    CF_DATA_SAVE(save, cf, data);
+    info->backend = Curl_ssl_backend();
+    info->internals = connssl->ssl_impl->get_internals(
+      cf->ctx, (query == CF_QUERY_SSL_INFO) ?
+      CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION);
+    CF_DATA_RESTORE(cf, save);
+    return CURLE_OK;
+  }
   default:
     break;
   }
@@ -1625,7 +1597,6 @@
   ssl_cf_connect,
   ssl_cf_close,
   ssl_cf_shutdown,
-  Curl_cf_def_get_host,
   ssl_cf_adjust_pollset,
   ssl_cf_data_pending,
   ssl_cf_send,
@@ -1646,7 +1617,6 @@
   ssl_cf_connect,
   ssl_cf_close,
   ssl_cf_shutdown,
-  Curl_cf_def_get_host,
   ssl_cf_adjust_pollset,
   ssl_cf_data_pending,
   ssl_cf_send,
@@ -1769,40 +1739,6 @@
   return (Curl_ssl->supports & ssl_option);
 }
 
-static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
-{
-  for(; cf; cf = cf->next) {
-    if(cf->cft == &Curl_cft_ssl)
-      return cf;
-#ifndef CURL_DISABLE_PROXY
-    if(cf->cft == &Curl_cft_ssl_proxy)
-      return cf;
-#endif
-  }
-  return NULL;
-}
-
-
-void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
-                             CURLINFO info, int n)
-{
-  void *result = NULL;
-  (void)n;
-  if(data->conn) {
-    struct Curl_cfilter *cf;
-    /* get first SSL filter in chain, if any is present */
-    cf = get_ssl_filter(data->conn->cfilter[sockindex]);
-    if(cf) {
-      struct ssl_connect_data *connssl = cf->ctx;
-      struct cf_call_data save;
-      CF_DATA_SAVE(save, cf, data);
-      result = connssl->ssl_impl->get_internals(cf->ctx, info);
-      CF_DATA_RESTORE(cf, save);
-    }
-  }
-  return result;
-}
-
 static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
                                        struct Curl_easy *data,
                                        bool send_shutdown, bool *done)
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index 0bb333b..c62b8ae 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -190,8 +190,6 @@
 
 bool Curl_ssl_cert_status_request(void);
 
-bool Curl_ssl_false_start(void);
-
 /* The maximum size of the SSL channel binding is 85 bytes, as defined in
  * RFC 5929, Section 4.1. The 'tls-server-end-point:' prefix is 21 bytes long,
  * and SHA-512 is the longest supported hash algorithm, with a digest length of
@@ -209,7 +207,7 @@
  * returned.
  */
 CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
-                                       struct dynbuf *binding);
+                                      struct dynbuf *binding);
 
 #define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
 
@@ -236,16 +234,6 @@
 bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option);
 
 /**
- * Get the internal ssl instance (like OpenSSL's SSL*) from the filter
- * chain at `sockindex` of type specified by `info`.
- * For `n` == 0, the first active (top down) instance is returned.
- * 1 gives the second active, etc.
- * NULL is returned when no active SSL filter is present.
- */
-void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
-                             CURLINFO info, int n);
-
-/**
  * Get the ssl_config_data in `data` that is relevant for cfilter `cf`.
  */
 struct ssl_config_data *Curl_ssl_cf_get_config(struct Curl_cfilter *cf,
@@ -274,8 +262,6 @@
 #define Curl_ssl_free_certinfo(x) Curl_nop_stmt
 #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
 #define Curl_ssl_cert_status_request() FALSE
-#define Curl_ssl_false_start() FALSE
-#define Curl_ssl_get_internals(a,b,c,d) NULL
 #define Curl_ssl_supports(a,b) FALSE
 #define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
 #define Curl_ssl_cfilter_remove(a,b,c) CURLE_OK
diff --git a/Utilities/cmcurl/lib/vtls/vtls_int.h b/Utilities/cmcurl/lib/vtls/vtls_int.h
index 0632a07..11987c3 100644
--- a/Utilities/cmcurl/lib/vtls/vtls_int.h
+++ b/Utilities/cmcurl/lib/vtls/vtls_int.h
@@ -127,6 +127,7 @@
   BIT(use_alpn);                    /* if ALPN shall be used in handshake */
   BIT(peer_closed);                 /* peer has closed connection */
   BIT(prefs_checked);               /* SSL preferences have been checked */
+  BIT(input_pending);               /* data for SSL_read() may be available */
 };
 
 
@@ -175,13 +176,12 @@
   CURLcode (*set_engine_default)(struct Curl_easy *data);
   struct curl_slist *(*engines_list)(struct Curl_easy *data);
 
-  bool (*false_start)(void);
   CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
                     unsigned char *sha256sum, size_t sha256sumlen);
-  ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
-                        char *buf, size_t len, CURLcode *code);
-  ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
-                        const void *mem, size_t len, CURLcode *code);
+  CURLcode (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
+                         char *buf, size_t len, size_t *pnread);
+  CURLcode (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
+                         const void *mem, size_t len, size_t *pnwritten);
 
   CURLcode (*get_channel_binding)(struct Curl_easy *data, int sockindex,
                                   struct dynbuf *binding);
diff --git a/Utilities/cmcurl/lib/vtls/vtls_scache.c b/Utilities/cmcurl/lib/vtls/vtls_scache.c
index 1fe4b5b..662539c 100644
--- a/Utilities/cmcurl/lib/vtls/vtls_scache.c
+++ b/Utilities/cmcurl/lib/vtls/vtls_scache.c
@@ -29,9 +29,6 @@
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
@@ -376,9 +373,9 @@
 }
 
 static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf,
-                                          const char *name,
-                                          char *path,
-                                          bool *is_local)
+                                         const char *name,
+                                         char *path,
+                                         bool *is_local)
 {
   if(path && path[0]) {
     /* We try to add absolute paths, so that the session key can stay
@@ -410,8 +407,8 @@
 }
 
 static CURLcode cf_ssl_peer_key_add_hash(struct dynbuf *buf,
-                                          const char *name,
-                                          struct curl_blob *blob)
+                                         const char *name,
+                                         struct curl_blob *blob)
 {
   CURLcode r = CURLE_OK;
   if(blob && blob->len) {
@@ -649,7 +646,7 @@
   /* check for entries with known peer_key */
   for(i = 0; scache && i < scache->peer_count; i++) {
     if(scache->peers[i].ssl_peer_key &&
-       strcasecompare(ssl_peer_key, scache->peers[i].ssl_peer_key) &&
+       curl_strequal(ssl_peer_key, scache->peers[i].ssl_peer_key) &&
        cf_ssl_scache_match_auth(&scache->peers[i], conn_config)) {
       /* yes, we have a cached session for this! */
       *ppeer = &scache->peers[i];
@@ -868,9 +865,9 @@
 }
 
 void Curl_ssl_scache_return(struct Curl_cfilter *cf,
-                           struct Curl_easy *data,
-                           const char *ssl_peer_key,
-                           struct Curl_ssl_session *s)
+                            struct Curl_easy *data,
+                            const char *ssl_peer_key,
+                            struct Curl_ssl_session *s)
 {
   /* See RFC 8446 C.4:
    * "Clients SHOULD NOT reuse a ticket for multiple connections." */
diff --git a/Utilities/cmcurl/lib/vtls/vtls_scache.h b/Utilities/cmcurl/lib/vtls/vtls_scache.h
index eef5080..deedccf 100644
--- a/Utilities/cmcurl/lib/vtls/vtls_scache.h
+++ b/Utilities/cmcurl/lib/vtls/vtls_scache.h
@@ -206,12 +206,6 @@
                                  void *userptr);
 
 #endif /* USE_SSLS_EXPORT */
-
-#else /* USE_SSL */
-
-#define Curl_ssl_scache_create(x,y,z) ((void)x, CURLE_OK)
-#define Curl_ssl_scache_destroy(x) do {} while(0)
-
-#endif /* USE_SSL (else) */
+#endif /* USE_SSL */
 
 #endif /* HEADER_CURL_VTLS_SCACHE_H */
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index 9c6f518..c3560e8 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -67,7 +67,6 @@
 #include "../connect.h" /* for the connect timeout */
 #include "../progress.h"
 #include "../select.h"
-#include "../strcase.h"
 #include "../strdup.h"
 #include "x509asn1.h"
 #include "../curl_printf.h"
@@ -227,9 +226,9 @@
 {
   if(!type || !type[0])
     return WOLFSSL_FILETYPE_PEM;
-  if(strcasecompare(type, "PEM"))
+  if(curl_strequal(type, "PEM"))
     return WOLFSSL_FILETYPE_PEM;
-  if(strcasecompare(type, "DER"))
+  if(curl_strequal(type, "DER"))
     return WOLFSSL_FILETYPE_ASN1;
   return -1;
 }
@@ -247,6 +246,9 @@
   { WOLFSSL_P256_ML_KEM_512, "P256_ML_KEM_512" },
   { WOLFSSL_P384_ML_KEM_768, "P384_ML_KEM_768" },
   { WOLFSSL_P521_ML_KEM_1024, "P521_ML_KEM_1024" },
+  { WOLFSSL_P256_ML_KEM_768, "P256_ML_KEM_768" },
+  { WOLFSSL_P384_ML_KEM_1024, "P384_ML_KEM_1024" },
+  { WOLFSSL_X25519_ML_KEM_768, "X25519_ML_KEM_768" },
   { 0, NULL }
 };
 #endif
@@ -319,7 +321,7 @@
   struct ssl_connect_data *connssl = cf->ctx;
   struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten, skiplen = 0;
+  size_t nwritten, skiplen = 0;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
@@ -333,21 +335,21 @@
     skiplen = (ssize_t)(blen - wssl->io_send_blocked_len);
     blen = wssl->io_send_blocked_len;
   }
-  nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
+  result = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &nwritten);
   wssl->io_result = result;
-  CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
-              blen, nwritten, result);
+  CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %d, %zu",
+              blen, result, nwritten);
 #ifdef USE_FULL_BIO
   wolfSSL_BIO_clear_retry_flags(bio);
 #endif
-  if(nwritten < 0 && CURLE_AGAIN == result) {
+  if(CURLE_AGAIN == result) {
     wolfSSL_BIO_set_retry_write(bio);
     if(wssl->shutting_down && !wssl->io_send_blocked_len)
       wssl->io_send_blocked_len = blen;
   }
   else if(!result && skiplen)
     nwritten += skiplen;
-  return (int)nwritten;
+  return result ? -1 : (int)nwritten;
 }
 
 static int wssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
@@ -356,7 +358,7 @@
   struct ssl_connect_data *connssl = cf->ctx;
   struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nread;
+  size_t nread;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
@@ -376,17 +378,17 @@
     }
   }
 
-  nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+  result = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread);
   wssl->io_result = result;
-  CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result);
+  CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %d, %zu", blen, result, nread);
 #ifdef USE_FULL_BIO
   wolfSSL_BIO_clear_retry_flags(bio);
 #endif
-  if(nread < 0 && CURLE_AGAIN == result)
+  if(CURLE_AGAIN == result)
     wolfSSL_BIO_set_retry_read(bio);
   else if(nread == 0)
     connssl->peer_closed = TRUE;
-  return (int)nread;
+  return result ? -1 : (int)nread;
 }
 
 static WOLFSSL_BIO_METHOD *wssl_bio_cf_method = NULL;
@@ -518,7 +520,7 @@
 #endif
 
   if(!connssl->earlydata_max) {
-    /* Seems to be GnuTLS way to signal no EarlyData in session */
+    /* Seems to be no WolfSSL way to signal no EarlyData in session */
     CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
   }
   else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
@@ -962,6 +964,7 @@
   size_t idx = 0;
 #endif
   CURLcode result = CURLE_FAILED_INIT;
+  unsigned char transport;
 
   DEBUGASSERT(!wctx->ssl_ctx);
   DEBUGASSERT(!wctx->ssl);
@@ -971,6 +974,8 @@
     goto out;
   }
   Curl_alpn_copy(&alpns, alpns_requested);
+  DEBUGASSERT(cf->next);
+  transport = Curl_conn_cf_get_transport(cf->next, data);
 
 #if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */
   req_method = wolfSSLv23_client_method();
@@ -1101,7 +1106,7 @@
 #endif
 
   curves = conn_config->curves;
-  if(!curves && cf->conn->transport == TRNSPRT_QUIC)
+  if(!curves && (transport == TRNSPRT_QUIC))
     curves = (char *)CURL_UNCONST(QUIC_GROUPS);
 
   if(curves) {
@@ -1242,8 +1247,7 @@
   }
 #endif
 
-  if(ssl_config->primary.cache_session &&
-     cf->conn->transport != TRNSPRT_QUIC) {
+  if(ssl_config->primary.cache_session && (transport != TRNSPRT_QUIC)) {
     /* Register to get notified when a new session is received */
     wolfSSL_CTX_sess_set_new_cb(wctx->ssl_ctx, wssl_vtls_new_session_cb);
   }
@@ -1289,7 +1293,7 @@
 
   wolfSSL_set_app_data(wctx->ssl, ssl_user_data);
 #ifdef WOLFSSL_QUIC
-  if(cf->conn->transport == TRNSPRT_QUIC)
+  if(transport == TRNSPRT_QUIC)
     wolfSSL_set_quic_use_legacy_codepoint(wctx->ssl, 0);
 #endif
 
@@ -1789,49 +1793,48 @@
   }
 }
 
-static ssize_t wssl_send(struct Curl_cfilter *cf,
-                         struct Curl_easy *data,
-                         const void *buf, size_t blen,
-                         CURLcode *curlcode)
+static CURLcode wssl_send(struct Curl_cfilter *cf,
+                          struct Curl_easy *data,
+                          const void *buf, size_t blen,
+                          size_t *pnwritten)
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
-  size_t total_written = 0;
-  ssize_t nwritten = -1;
-  DEBUGASSERT(wssl);
+  CURLcode result = CURLE_OK;
+  int nwritten;
 
+  DEBUGASSERT(wssl);
+  *pnwritten = 0;
   wolfSSL_ERR_clear_error();
 
   if(blen) {
     int memlen = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
-    int rc;
 
-    rc = wolfSSL_write(wssl->ssl, buf, memlen);
-    if(rc <= 0) {
-      int err = wolfSSL_get_error(wssl->ssl, rc);
+    nwritten = wolfSSL_write(wssl->ssl, buf, memlen);
+
+    if(nwritten > 0)
+      *pnwritten += (size_t)nwritten;
+    else {
+      int err = wolfSSL_get_error(wssl->ssl, nwritten);
 
       switch(err) {
       case WOLFSSL_ERROR_WANT_READ:
       case WOLFSSL_ERROR_WANT_WRITE:
         /* there is data pending, re-invoke wolfSSL_write() */
-        if(total_written) {
-          *curlcode = CURLE_OK;
-          nwritten = total_written;
+        if(*pnwritten) {
+          result = CURLE_OK;
           goto out;
         }
-        *curlcode = CURLE_AGAIN;
-        nwritten = -1;
+        result = CURLE_AGAIN;
         goto out;
 
       default:
         if(wssl->io_result == CURLE_AGAIN) {
-          if(total_written) {
-            *curlcode = CURLE_OK;
-            nwritten = total_written;
+          if(*pnwritten) {
+            result = CURLE_OK;
             goto out;
           }
-          *curlcode = CURLE_AGAIN;
-          nwritten = -1;
+          result = CURLE_AGAIN;
           goto out;
         }
         {
@@ -1841,21 +1844,16 @@
                               sizeof(error_buffer)),
                 SOCKERRNO);
         }
-        *curlcode = CURLE_SEND_ERROR;
-        nwritten = -1;
+        result = CURLE_SEND_ERROR;
         goto out;
       }
     }
-    else
-      total_written += rc;
   }
 
-  *curlcode = CURLE_OK;
-  nwritten = total_written;
 out:
-  CURL_TRC_CF(data, cf, "wssl_send(len=%zu) -> %" FMT_OFF_T ", %d",
-              blen, nwritten, *curlcode);
-  return nwritten;
+  CURL_TRC_CF(data, cf, "wssl_send(len=%zu) -> %d, %zu",
+              blen, result, *pnwritten);
+  return result;
 }
 
 static CURLcode wssl_shutdown(struct Curl_cfilter *cf,
@@ -1982,10 +1980,10 @@
   }
 }
 
-static ssize_t wssl_recv(struct Curl_cfilter *cf,
-                         struct Curl_easy *data,
-                         char *buf, size_t blen,
-                         CURLcode *curlcode)
+static CURLcode wssl_recv(struct Curl_cfilter *cf,
+                          struct Curl_easy *data,
+                          char *buf, size_t blen,
+                          size_t *pnread)
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
@@ -1994,41 +1992,38 @@
 
   DEBUGASSERT(wssl);
 
+  *pnread = 0;
   wolfSSL_ERR_clear_error();
-  *curlcode = CURLE_OK;
 
   nread = wolfSSL_read(wssl->ssl, buf, buffsize);
 
-  if(nread <= 0) {
+  if(nread > 0)
+    *pnread = (size_t)nread;
+  else {
     int err = wolfSSL_get_error(wssl->ssl, nread);
 
     switch(err) {
     case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
       CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
-      *curlcode = CURLE_OK;
-      return 0;
+      return CURLE_OK;
     case WOLFSSL_ERROR_NONE:
     case WOLFSSL_ERROR_WANT_READ:
     case WOLFSSL_ERROR_WANT_WRITE:
       if(!wssl->io_result && connssl->peer_closed) {
         CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
-        *curlcode = CURLE_OK;
-        return 0;
+        return CURLE_OK;
       }
       /* there is data pending, re-invoke wolfSSL_read() */
       CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen);
-      *curlcode = CURLE_AGAIN;
-      return -1;
+      return CURLE_AGAIN;
     default:
       if(wssl->io_result == CURLE_AGAIN) {
         CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen);
-        *curlcode = CURLE_AGAIN;
-        return -1;
+        return CURLE_AGAIN;
       }
       else if(!wssl->io_result && connssl->peer_closed) {
         CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
-        *curlcode = CURLE_OK;
-        return 0;
+        failf(data, "Connection closed abruptly");
       }
       else {
         char error_buffer[256];
@@ -2037,13 +2032,12 @@
                             sizeof(error_buffer)),
               SOCKERRNO);
       }
-      *curlcode = CURLE_RECV_ERROR;
-      return -1;
+      return CURLE_RECV_ERROR;
     }
   }
 
-  CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> %d", blen, nread);
-  return nread;
+  CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> 0, %zu", blen, *pnread);
+  return CURLE_OK;
 }
 
 size_t Curl_wssl_version(char *buffer, size_t size)
@@ -2095,6 +2089,18 @@
     return FALSE;
 }
 
+void Curl_wssl_report_handshake(struct Curl_easy *data,
+                                struct wssl_ctx *wssl)
+{
+#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
+    infof(data, "SSL connection using %s / %s",
+          wolfSSL_get_version(wssl->ssl),
+          wolfSSL_get_cipher_name(wssl->ssl));
+#else
+    infof(data, "SSL connected");
+#endif
+}
+
 static CURLcode wssl_connect(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              bool *done)
@@ -2168,16 +2174,9 @@
     }
 #endif /* HAVE_ALPN */
 
-#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
-    infof(data, "SSL connection using %s / %s",
-          wolfSSL_get_version(wssl->ssl),
-          wolfSSL_get_cipher_name(wssl->ssl));
-#else
-    infof(data, "SSL connected");
-#endif
-
     connssl->connecting_state = ssl_connect_done;
     connssl->state = ssl_connection_complete;
+    Curl_wssl_report_handshake(data, wssl);
 
 #ifdef WOLFSSL_EARLY_DATA
     if(connssl->earlydata_state > ssl_earlydata_none) {
@@ -2286,7 +2285,6 @@
   NULL,                            /* set_engine */
   NULL,                            /* set_engine_default */
   NULL,                            /* engines_list */
-  NULL,                            /* false_start */
   wssl_sha256sum,                  /* sha256sum */
   wssl_recv,                       /* recv decrypted data */
   wssl_send,                       /* send data to encrypt */
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.h b/Utilities/cmcurl/lib/vtls/wolfssl.h
index 0ddbee9..19ca609 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.h
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.h
@@ -88,6 +88,8 @@
                                  struct Curl_easy *data,
                                  struct wssl_ctx *wssl);
 
+void Curl_wssl_report_handshake(struct Curl_easy *data,
+                                struct wssl_ctx *wssl);
 
 #endif /* USE_WOLFSSL */
 #endif /* HEADER_CURL_WOLFSSL_H */
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c
index c6246cb..fe47e81 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.c
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.c
@@ -24,23 +24,21 @@
 
 #include "../curl_setup.h"
 
-#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) ||      \
-  defined(USE_SCHANNEL) || defined(USE_SECTRANSP) ||    \
+#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
   defined(USE_MBEDTLS) || defined(USE_RUSTLS)
 
-#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
-  defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_RUSTLS)
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) || \
+  defined(USE_WOLFSSL) || defined(USE_RUSTLS)
 #define WANT_PARSEX509 /* uses Curl_parseX509() */
 #endif
 
-#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
-  defined(USE_MBEDTLS) || defined(USE_RUSTLS)
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) || \
+  defined(USE_RUSTLS)
 #define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
 #endif
 
 #include <curl/curl.h>
 #include "../urldata.h"
-#include "../strcase.h"
 #include "../curl_ctype.h"
 #include "hostcheck.h"
 #include "vtls.h"
@@ -263,7 +261,7 @@
 {
   const struct Curl_OID *op;
   for(op = OIDtable; op->numoid; op++)
-    if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid))
+    if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid))
       return op;
 
   return NULL;
@@ -591,7 +589,7 @@
  * Return error code.
  */
 static CURLcode UTime2str(struct dynbuf *store,
-                             const char *beg, const char *end)
+                          const char *beg, const char *end)
 {
   const char *tzp;
   size_t tzl;
@@ -861,7 +859,7 @@
   if(!getASN1Element(&cert->subjectPublicKey, ccp,
                      cert->subjectPublicKeyInfo.end))
     return -1;
-  /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
+  /* Get optional issuerUniqueID, subjectUniqueID and extensions. */
   cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
   cert->extensions.tag = elem.tag = 0;
   cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL;
@@ -990,7 +988,7 @@
 
   /* Generate all information records for the public key. */
 
-  if(strcasecompare(algo, "ecPublicKey")) {
+  if(curl_strequal(algo, "ecPublicKey")) {
     /*
      * ECC public key is all the data, a value of type BIT STRING mapped to
      * OCTET STRING and should not be parsed as an ASN.1 value.
@@ -1012,7 +1010,7 @@
   if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
     return 1;
 
-  if(strcasecompare(algo, "rsaEncryption")) {
+  if(curl_strequal(algo, "rsaEncryption")) {
     const char *q;
     size_t len;
 
@@ -1047,7 +1045,7 @@
     if(do_pubkey_field(data, certnum, "rsa(e)", &elem))
       return 1;
   }
-  else if(strcasecompare(algo, "dsa")) {
+  else if(curl_strequal(algo, "dsa")) {
     p = getASN1Element(&elem, param->beg, param->end);
     if(p) {
       if(do_pubkey_field(data, certnum, "dsa(p)", &elem))
@@ -1065,7 +1063,7 @@
       }
     }
   }
-  else if(strcasecompare(algo, "dhpublicnumber")) {
+  else if(curl_strequal(algo, "dhpublicnumber")) {
     p = getASN1Element(&elem, param->beg, param->end);
     if(p) {
       if(do_pubkey_field(data, certnum, "dh(p)", &elem))
@@ -1277,5 +1275,5 @@
 
 #endif /* WANT_EXTRACT_CERTINFO */
 
-#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP
-          or USE_MBEDTLS or USE_RUSTLS */
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_MBEDTLS or
+          USE_RUSTLS */
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.h b/Utilities/cmcurl/lib/vtls/x509asn1.h
index 1c9c35c..f9bd455 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.h
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.h
@@ -27,8 +27,7 @@
 
 #include "../curl_setup.h"
 
-#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
-  defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
+#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
   defined(USE_MBEDTLS) || defined(USE_RUSTLS)
 
 #include "../cfilters.h"
@@ -79,8 +78,8 @@
                          const char *beg, const char *end);
 
 #ifdef UNITTESTS
-#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
-  defined(USE_MBEDTLS) || defined(USE_RUSTLS)
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) || \
+  defined(USE_RUSTLS)
 
 /* used by unit1656.c */
 CURLcode Curl_x509_GTime2str(struct dynbuf *store,
@@ -91,6 +90,6 @@
 #endif
 #endif
 
-#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP
-          or USE_MBEDTLS or USE_RUSTLS */
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_MBEDTLS or
+          USE_RUSTLS */
 #endif /* HEADER_CURL_X509ASN1_H */
diff --git a/Utilities/cmcurl/lib/ws.c b/Utilities/cmcurl/lib/ws.c
index fc02025..7f8a688 100644
--- a/Utilities/cmcurl/lib/ws.c
+++ b/Utilities/cmcurl/lib/ws.c
@@ -543,7 +543,7 @@
     ws_dec_info(dec, data, "passing");
     if(result)
       return result;
-    /* paylod parsing done */
+    /* payload parsing done */
     dec->state = WS_DEC_INIT;
     break;
   default:
@@ -653,11 +653,11 @@
   }
 
   if(nbytes) {
-    ssize_t nwritten;
-    nwritten = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf,
-                               nbytes, &result);
-    if(nwritten < 0) {
-      infof(data, "[WS] error adding data to buffer %d", result);
+    size_t nwritten;
+    result = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf,
+                             nbytes, &nwritten);
+    if(result) {
+      infof(data, "WS: error adding data to buffer %d", result);
       return result;
     }
   }
@@ -756,8 +756,7 @@
 {
   unsigned char firstbyte = 0;
   unsigned char head[14];
-  size_t hlen;
-  ssize_t n;
+  size_t hlen, n;
 
   if(payload_len < 0) {
     failf(data, "[WS] starting new frame with negative payload length %"
@@ -837,16 +836,16 @@
   /* reset for payload to come */
   enc->xori = 0;
 
-  n = Curl_bufq_write(out, head, hlen, err);
-  if(n < 0)
+  *err = Curl_bufq_write(out, head, hlen, &n);
+  if(*err)
     return -1;
-  if((size_t)n != hlen) {
+  if(n != hlen) {
     /* We use a bufq with SOFT_LIMIT, writing should always succeed */
     DEBUGASSERT(0);
     *err = CURLE_SEND_ERROR;
     return -1;
   }
-  return n;
+  return (ssize_t)n;
 }
 
 static ssize_t ws_enc_write_payload(struct ws_encoder *enc,
@@ -854,8 +853,7 @@
                                     const unsigned char *buf, size_t buflen,
                                     struct bufq *out, CURLcode *err)
 {
-  ssize_t n;
-  size_t i, len;
+  size_t i, len, n;
 
   if(Curl_bufq_is_full(out)) {
     *err = CURLE_AGAIN;
@@ -869,8 +867,8 @@
 
   for(i = 0; i < len; ++i) {
     unsigned char c = buf[i] ^ enc->mask[enc->xori];
-    n = Curl_bufq_write(out, &c, 1, err);
-    if(n < 0) {
+    *err = Curl_bufq_write(out, &c, 1, &n);
+    if(*err) {
       if((*err != CURLE_AGAIN) || !i)
         return -1;
       break;
@@ -1054,15 +1052,16 @@
   }
 
   if(data->set.connect_only) {
-    ssize_t nwritten;
+    size_t nwritten;
     /* In CONNECT_ONLY setup, the payloads from `mem` need to be received
      * when using `curl_ws_recv` later on after this transfer is already
      * marked as DONE. */
-    nwritten = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem,
-                               nread, &result);
-    if(nwritten < 0)
+    result = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem,
+                             nread, &nwritten);
+    if(result)
       return result;
-    CURL_TRC_WS(data, "%zu bytes payload", nread);
+    DEBUGASSERT(nread == nwritten);
+    infof(data, "%zu bytes websocket payload", nread);
   }
   else { /* !connect_only */
     /* And pass any additional data to the writers */
@@ -1137,22 +1136,17 @@
   return nwritten;
 }
 
-static ssize_t nw_in_recv(void *reader_ctx,
-                          unsigned char *buf, size_t buflen,
-                          CURLcode *err)
+static CURLcode nw_in_recv(void *reader_ctx,
+                           unsigned char *buf, size_t buflen,
+                           size_t *pnread)
 {
   struct Curl_easy *data = reader_ctx;
-  size_t nread;
-
-  *err = curl_easy_recv(data, buf, buflen, &nread);
-  if(*err)
-    return -1;
-  return (ssize_t)nread;
+  return curl_easy_recv(data, buf, buflen, pnread);
 }
 
-CURL_EXTERN CURLcode curl_ws_recv(CURL *d, void *buffer,
-                                  size_t buflen, size_t *nread,
-                                  const struct curl_ws_frame **metap)
+CURLcode curl_ws_recv(CURL *d, void *buffer,
+                      size_t buflen, size_t *nread,
+                      const struct curl_ws_frame **metap)
 {
   struct Curl_easy *data = d;
   struct connectdata *conn = data->conn;
@@ -1192,10 +1186,10 @@
 
     /* receive more when our buffer is empty */
     if(Curl_bufq_is_empty(&ws->recvbuf)) {
-      ssize_t n = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &result);
-      if(n < 0) {
+      size_t n;
+      result = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &n);
+      if(result)
         return result;
-      }
       else if(n == 0) {
         /* connection closed */
         infof(data, "[WS] connection expectedly closed?");
@@ -1373,10 +1367,10 @@
   return result;
 }
 
-CURL_EXTERN CURLcode curl_ws_send(CURL *d, const void *buffer_arg,
-                                  size_t buflen, size_t *sent,
-                                  curl_off_t fragsize,
-                                  unsigned int flags)
+CURLcode curl_ws_send(CURL *d, const void *buffer_arg,
+                      size_t buflen, size_t *sent,
+                      curl_off_t fragsize,
+                      unsigned int flags)
 {
   struct websocket *ws;
   const unsigned char *buffer = buffer_arg;
@@ -1527,7 +1521,7 @@
 }
 
 
-CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *d)
+const struct curl_ws_frame *curl_ws_meta(CURL *d)
 {
   /* we only return something for websocket, called from within the callback
      when not using raw mode */
@@ -1600,9 +1594,9 @@
 
 #else
 
-CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
-                                  size_t *nread,
-                                  const struct curl_ws_frame **metap)
+CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
+                      size_t *nread,
+                      const struct curl_ws_frame **metap)
 {
   (void)curl;
   (void)buffer;
@@ -1612,10 +1606,10 @@
   return CURLE_NOT_BUILT_IN;
 }
 
-CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer,
-                                  size_t buflen, size_t *sent,
-                                  curl_off_t fragsize,
-                                  unsigned int flags)
+CURLcode curl_ws_send(CURL *curl, const void *buffer,
+                      size_t buflen, size_t *sent,
+                      curl_off_t fragsize,
+                      unsigned int flags)
 {
   (void)curl;
   (void)buffer;
@@ -1626,7 +1620,7 @@
   return CURLE_NOT_BUILT_IN;
 }
 
-CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *data)
+const struct curl_ws_frame *curl_ws_meta(CURL *data)
 {
   (void)data;
   return NULL;
diff --git a/Utilities/cmlibrhash/librhash/byte_order.h b/Utilities/cmlibrhash/librhash/byte_order.h
index 73863e0..6e6549e 100644
--- a/Utilities/cmlibrhash/librhash/byte_order.h
+++ b/Utilities/cmlibrhash/librhash/byte_order.h
@@ -77,7 +77,7 @@
 #elif defined(CPU_IA32) || defined(CPU_X64) || defined(__ia64) || defined(__ia64__) || \
       defined(__alpha__) || defined(_M_ALPHA) || defined(vax) || defined(MIPSEL) || \
       defined(_ARM_) || defined(__arm__) || defined(_M_ARM64) || defined(_M_ARM64EC) || \
-      defined(__loongarch64)
+      defined(__loongarch64) || defined(__sw_64)
 #  define RHASH_BYTE_ORDER RHASH_BYTE_ORDER_LE
 #elif defined(__sparc) || defined(__sparc__) || defined(sparc) || \
       defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_POWER) || \